[关闭]
@Tyhj 2019-01-31T07:20:57.000000Z 字数 4092 阅读 766

策略模式

设计模式


原文:https://www.jianshu.com/p/c0dadeacd68f

定义

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

使用场景

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

理解

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

实现方法

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

举个栗子

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

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

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

  1. public interface LikeColor {
  2. /**
  3. * 两种颜色是否相似
  4. *
  5. * @param color1
  6. * @param color2
  7. * @param aberration 允许差异值
  8. * @return
  9. */
  10. boolean isLike(int color1, int color2, double aberration);
  11. }

实现HSV颜色空间算法

  1. public class HsvColorLike implements LikeColor {
  2. @Override
  3. public boolean isLike(int color1, int color2, double aberration) {
  4. if (hsvAberration(color1, color2) <= aberration) {
  5. return true;
  6. }
  7. return false;
  8. }
  9. /**
  10. * HSV颜色空间计算颜色距离
  11. */
  12. public static double hsvAberration(int color1, int color2) {
  13. float[] tempHSV1 = new float[3];
  14. Color.colorToHSV(color1, tempHSV1);
  15. float[] tempHSV2 = new float[3];
  16. Color.colorToHSV(color2, tempHSV2);
  17. HSV hsv1 = new HSV();
  18. hsv1.H = tempHSV1[0];
  19. hsv1.S = tempHSV1[1];
  20. hsv1.V = tempHSV1[2];
  21. HSV hsv2 = new HSV();
  22. hsv2.H = tempHSV2[0];
  23. hsv2.S = tempHSV2[1];
  24. hsv2.V = tempHSV2[2];
  25. return HSV.distanceOf(hsv1, hsv2);
  26. }
  27. public static class HSV {
  28. public float H;
  29. public float S;
  30. public float V;
  31. //self-defined
  32. private static final double R = 100;
  33. private static final double angle = 30;
  34. private static final double h = R * Math.cos(angle / 180 * Math.PI);
  35. private static final double r = R * Math.sin(angle / 180 * Math.PI);
  36. /**
  37. * HSV颜色空间计算颜色距离
  38. * HSV是个六棱锥模型,这个模型中颜色的参数分别是:色调(H),饱和度(S),明度(V)
  39. *
  40. * @param hsv1
  41. * @param hsv2
  42. * @return
  43. */
  44. public static double distanceOf(HSV hsv1, HSV hsv2) {
  45. double x1 = r * hsv1.V * hsv1.S * Math.cos(hsv1.H / 180 * Math.PI);
  46. double y1 = r * hsv1.V * hsv1.S * Math.sin(hsv1.H / 180 * Math.PI);
  47. double z1 = h * (1 - hsv1.V);
  48. double x2 = r * hsv2.V * hsv2.S * Math.cos(hsv2.H / 180 * Math.PI);
  49. double y2 = r * hsv2.V * hsv2.S * Math.sin(hsv2.H / 180 * Math.PI);
  50. double z2 = h * (1 - hsv2.V);
  51. double dx = x1 - x2;
  52. double dy = y1 - y2;
  53. double dz = z1 - z2;
  54. return Math.sqrt(dx * dx + dy * dy + dz * dz);
  55. }
  56. }
  57. }

实现LAB颜色空间算法

  1. public class LabColorLike implements LikeColor {
  2. @Override
  3. public boolean isLike(int color1, int color2, double aberration) {
  4. if (labAberration(color1, color2) <= aberration) {
  5. return true;
  6. }
  7. return false;
  8. }
  9. /**
  10. * LAB颜色空间计算色差,基于人眼对颜色的感知,
  11. * 可以表示人眼所能感受到的所有颜色。
  12. * L表示明度,A表示红绿色差,B表示蓝黄色差
  13. */
  14. public static int labAberration(int color1, int color2) {
  15. int r1 = Color.red(color1); // 取高两位
  16. int g1 = Color.green(color1);// 取中两位
  17. int b1 = Color.blue(color1);// 取低两位
  18. int r2 = Color.red(color2); // 取高两位
  19. int g2 = Color.green(color2);// 取中两位
  20. int b2 = Color.blue(color2);// 取低两位
  21. int rmean = (r1 + r2) / 2;
  22. int r = r1 - r2;
  23. int g = g1 - g2;
  24. int b = b1 - b2;
  25. return (int) Math.sqrt((2 + rmean / 256) * (Math.pow(r, 2)) + 4 * (Math.pow(g, 2)) + (2 + (255 - rmean) / 256) * (Math.pow(b, 2)));
  26. }
  27. }

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

  1. public class RgbColorLike implements LikeColor {
  2. @Override
  3. public boolean isLike(int color1, int color2, double aberration) {
  4. return baseLike(color1, color2, aberration);
  5. }
  6. /**
  7. * @param color1 第一种颜色
  8. * @param color2 第二种颜色
  9. * @return
  10. */
  11. public boolean baseLike(int color1, int color2, double aberration) {
  12. int red = Color.red(color1); // 取高两位
  13. int green = Color.green(color1);// 取中两位
  14. int blue = Color.blue(color1);// 取低两位
  15. int red2 = Color.red(color2); // 取高两位
  16. int green2 = Color.green(color2);// 取中两位
  17. int blue2 = Color.blue(color2);// 取低两位
  18. if (red == red2 && green == green2 && blue == blue2) {
  19. return true;
  20. }
  21. if ((Math.abs(red - red2) < aberration && Math.abs(green - green2) < aberration && Math.abs(blue - blue2) < aberration) &&
  22. (Math.abs(red - red2) + Math.abs(green - green2) + Math.abs(blue - blue2)) < aberration * 2.5) {
  23. return true;
  24. }
  25. return false;
  26. }
  27. /**
  28. * 简单的RGB颜色判断
  29. *
  30. * @return
  31. */
  32. public static void rgbAberration(int color1, int color2) {
  33. int red1 = Color.red(color1); // 取高两位
  34. int green1 = Color.green(color1);// 取中两位
  35. int blue1 = Color.blue(color1);// 取低两位
  36. int red2 = Color.red(color2); // 取高两位
  37. int green2 = Color.green(color2);// 取中两位
  38. int blue2 = Color.blue(color2);// 取低两位
  39. int red = Math.abs(red1 - red2);
  40. int green = Math.abs(green1 - green2);
  41. int blue = Math.abs(blue1 - blue2);
  42. LogUtils.e("RGB颜色判断:色差:" + red + "," + green + "," + blue + ",all:" + (red + green + blue));
  43. }
  44. }

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

  1. /**
  2. * 对比颜色
  3. *
  4. * @param color1
  5. * @param color2
  6. * @param aberration
  7. * @return
  8. */
  9. public static boolean colorLike(int color1, int color2, int aberration, LikeColor labLike) {
  10. return labLike.isLike(color1, color2, aberration);
  11. }

总结

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

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注