@Tyhj
2019-01-31T15:20:57.000000Z
字数 4092
阅读 785
设计模式
策略模式定义了一系列的算法,并将每个算法封装起来,而且使它们还可以相互替换。
- 针对同一种问题的多种处理方式,仅仅是具体行为有差别时
- 需要安全地封装同一种类型的操作的时候
- 出现同一抽象类有多个子类,而又需要使用if-else 或者 swith-case来选择具体子类时
其实就是当有多种策略来解决问题的时候,我们封装每一种方法,然后让它可以相互替换,这样增强程序的可拓展性、可维护性;
实现方法其实一般就是抽象出策略接口来,每一种具体的策略去实现接口,这样封装了每个策略;实现了同一个接口,所以可以相互替换
这个模式其实非常常见,比如图片加载框架中,图片可以被缓存在内存中、缓存在本地文件中、保存到服务器;那么获取图片的时候,也可以从缓存中找,从本地文件找,从服务器取;开闭原则这篇文章里面已经讲过了,这其实就是一个策略模式的例子
重新举一个例子,微信跳一跳在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);
}
理解起来很简单,平时应该也会频繁用到,遵循单一职责原则和开闭原则,增强了程序的可拓展性,可维护性。