美文网首页
策略模式

策略模式

作者: Tyhj | 来源:发表于2019-01-31 10:39 被阅读0次

    定义

    策略模式定义了一系列的算法,并将每个算法封装起来,而且使它们还可以相互替换。

    使用场景

    • 针对同一种问题的多种处理方式,仅仅是具体行为有差别时
    • 需要安全地封装同一种类型的操作的时候
    • 出现同一抽象类有多个子类,而又需要使用if-else 或者 swith-case来选择具体子类时

    理解

    其实就是当有多种策略来解决问题的时候,我们封装每一种方法,然后让它可以相互替换,这样增强程序的可拓展性、可维护性;

    实现方法

    实现方法其实一般就是抽象出策略接口来,每一种具体的策略去实现接口,这样封装了每个策略;实现了同一个接口,所以可以相互替换

    image

    举个栗子

    这个模式其实非常常见,比如图片加载框架中,图片可以被缓存在内存中、缓存在本地文件中、保存到服务器;那么获取图片的时候,也可以从缓存中找,从本地文件找,从服务器取;开闭原则这篇文章里面已经讲过了,这其实就是一个策略模式的例子

    重新举一个例子,微信跳一跳在2017年年末的时候很火,跳一跳外挂也很火,之前也根据颜色识别写了Android上实现微信跳一跳外挂;其中最主要的就是颜色识别,计算两种颜色的相似度,算法大概试了三种;

    首先抽象出颜色相似的接口

    public interface LikeColor {
        /**
         * 两种颜色是否相似
         *
         * @param color1
         * @param color2
         * @param aberration 允许差异值
         * @return
         */
        boolean isLike(int color1, int color2, double aberration);
    }
    

    实现HSV颜色空间算法

    public class HsvColorLike implements LikeColor {
    
        @Override
        public boolean isLike(int color1, int color2, double aberration) {
            if (hsvAberration(color1, color2) <= aberration) {
                return true;
            }
            return false;
        }
        
        /**
         * HSV颜色空间计算颜色距离
         */
        public static double hsvAberration(int color1, int color2) {
            float[] tempHSV1 = new float[3];
            Color.colorToHSV(color1, tempHSV1);
            float[] tempHSV2 = new float[3];
            Color.colorToHSV(color2, tempHSV2);
            HSV hsv1 = new HSV();
            hsv1.H = tempHSV1[0];
            hsv1.S = tempHSV1[1];
            hsv1.V = tempHSV1[2];
            HSV hsv2 = new HSV();
            hsv2.H = tempHSV2[0];
            hsv2.S = tempHSV2[1];
            hsv2.V = tempHSV2[2];
            return HSV.distanceOf(hsv1, hsv2);
        }
    
        
        public static class HSV {
            public float H;
            public float S;
            public float V;
    
            //self-defined
            private static final double R = 100;
            private static final double angle = 30;
            private static final double h = R * Math.cos(angle / 180 * Math.PI);
            private static final double r = R * Math.sin(angle / 180 * Math.PI);
    
            /**
             * HSV颜色空间计算颜色距离
             * HSV是个六棱锥模型,这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V)
             *
             * @param hsv1
             * @param hsv2
             * @return
             */
            public static double distanceOf(HSV hsv1, HSV hsv2) {
                double x1 = r * hsv1.V * hsv1.S * Math.cos(hsv1.H / 180 * Math.PI);
                double y1 = r * hsv1.V * hsv1.S * Math.sin(hsv1.H / 180 * Math.PI);
                double z1 = h * (1 - hsv1.V);
                double x2 = r * hsv2.V * hsv2.S * Math.cos(hsv2.H / 180 * Math.PI);
                double y2 = r * hsv2.V * hsv2.S * Math.sin(hsv2.H / 180 * Math.PI);
                double z2 = h * (1 - hsv2.V);
                double dx = x1 - x2;
                double dy = y1 - y2;
                double dz = z1 - z2;
                return Math.sqrt(dx * dx + dy * dy + dz * dz);
            }
        }
    }
    

    实现LAB颜色空间算法

    public class LabColorLike implements LikeColor {
    
        @Override
        public boolean isLike(int color1, int color2, double aberration) {
            if (labAberration(color1, color2) <= aberration) {
                return true;
            }
            return false;
        }
        
        /**
         * LAB颜色空间计算色差,基于人眼对颜色的感知,
         * 可以表示人眼所能感受到的所有颜色。
         * L表示明度,A表示红绿色差,B表示蓝黄色差
         */
        public static int labAberration(int color1, int color2) {
            int r1 = Color.red(color1); // 取高两位
            int g1 = Color.green(color1);// 取中两位
            int b1 = Color.blue(color1);// 取低两位
            int r2 = Color.red(color2); // 取高两位
            int g2 = Color.green(color2);// 取中两位
            int b2 = Color.blue(color2);// 取低两位
    
            int rmean = (r1 + r2) / 2;
            int r = r1 - r2;
            int g = g1 - g2;
            int b = b1 - b2;
            return (int) Math.sqrt((2 + rmean / 256) * (Math.pow(r, 2)) + 4 * (Math.pow(g, 2)) + (2 + (255 - rmean) / 256) * (Math.pow(b, 2)));
        }
    }
    

    最后自己也写了一个基于RGB的简单的颜色算法

    public class RgbColorLike implements LikeColor {
        @Override
        public boolean isLike(int color1, int color2, double aberration) {
            return baseLike(color1, color2, aberration);
        }
    
    
        /**
         * @param color1 第一种颜色
         * @param color2 第二种颜色
         * @return
         */
        public  boolean baseLike(int color1, int color2, double aberration) {
            int red = Color.red(color1); // 取高两位
            int green = Color.green(color1);// 取中两位
            int blue = Color.blue(color1);// 取低两位
            int red2 = Color.red(color2); // 取高两位
            int green2 = Color.green(color2);// 取中两位
            int blue2 = Color.blue(color2);// 取低两位
            if (red == red2 && green == green2 && blue == blue2) {
                return true;
            }
            if ((Math.abs(red - red2) < aberration && Math.abs(green - green2) < aberration && Math.abs(blue - blue2) < aberration) &&
                    (Math.abs(red - red2) + Math.abs(green - green2) + Math.abs(blue - blue2)) < aberration * 2.5) {
                return true;
            }
            return false;
        }
    
    
        /**
         * 简单的RGB颜色判断
         *
         * @return
         */
        public static void rgbAberration(int color1, int color2) {
            int red1 = Color.red(color1); // 取高两位
            int green1 = Color.green(color1);// 取中两位
            int blue1 = Color.blue(color1);// 取低两位
            int red2 = Color.red(color2); // 取高两位
            int green2 = Color.green(color2);// 取中两位
            int blue2 = Color.blue(color2);// 取低两位
    
            int red = Math.abs(red1 - red2);
            int green = Math.abs(green1 - green2);
            int blue = Math.abs(blue1 - blue2);
            LogUtils.e("RGB颜色判断:色差:" + red + "," + green + "," + blue + ",all:" + (red + green + blue));
        }
    
    }
    

    对比颜色的时候就可以随意调用任意一种算法

     /**
         * 对比颜色
         *
         * @param color1
         * @param color2
         * @param aberration
         * @return
         */
        public static boolean colorLike(int color1, int color2, int aberration, LikeColor labLike) {
            return labLike.isLike(color1, color2, aberration);
        }
    

    总结

    理解起来很简单,平时应该也会频繁用到,遵循单一职责原则和开闭原则,增强了程序的可拓展性,可维护性。

    相关文章

      网友评论

          本文标题:策略模式

          本文链接:https://www.haomeiwen.com/subject/bolksqtx.html