策略模式

简介

  • 策略模式定义了算法家族,分别封装起来,让他们之间可以相互替换。此模式让算法变化不会影响到使用算法的客户。
  • 策略模式的组成:
    • 抽象策略类:定义了策略的通用接口。
    • 具体策略类:包装了相关的算法和行为。
    • 上下文环境:持有一个策略类的引用,最终给客户端调用。

实例

  • 本Demo的UML图:


    UML图.png
    • CashSuper:抽象策略类,定义了抽象方法calCash()。
    • CashNormal等:具体策略类,包装了不同的算法行为。
    • CashContext:上下文环境,持有CashSuper对象。
  • 具体实现如下:
    • CashContext:
    public class CashContext {
    
      private CashSuper mCash;
    
      public CashContext(CashSuper mCash) {
          this.mCash = mCash;
      }
    
      public double getResult(double a) {
          return mCash.calCash(a);
      }
    
    }
    
    • CashSuper:
    public abstract class CashSuper {
    
      public abstract double calCash(double a);
    
    }
    
    • CashNormal:
    public class CashNormal extends CashSuper {
      @Override
     public double calCash(double a) {
          return a;
      }
    }
    
    • CashDisc:
    public class CashDisc extends CashSuper {
    
      private double pre = 1.0;
    
      public CashDisc(double pre) {
          this.pre = pre;
      }
    
      @Override
      public double calCash(double a) {
          return a * pre;
      }
    }
    
    • CashSub:
    public class CashSub extends CashSuper {
    
      private double full;
      private double sub;
    
      public CashSub(double full, double sub) {
          this.full = full;
          this.sub = sub;
      }
    
      @Override
      public double calCash(double a) {
          if (a >= full) {
              a = a - (a/full) * sub;
          }
          return a;
      }
    }
    
    • CashMain:测试类
    public class CashMain {
    
      public static void main(String args[]) {
          CashContext context = null;
          switch (args[0]) {
              case "正常收费":
                  context = new CashContext(new CashNormal());
                  break;
              case "满800减300":
                  context = new CashContext(new CashSub(800,300));
                  break;
              case "打8折":
                  context = new CashContext(new CashDisc(0.8));
                  break;
          }
          if (context != null) {
              System.out.print("单价800的商品售价:" + context.getResult(800));
          }
      }
    
    }
    
  • 运行结果:
单价800的商品售价:640.0
Process finished with exit code 0

和简单工厂模式的结合

  • 将选择算法策略的操作放在Context中,即把工厂类的功能整合在Context类,可将客户端代码与具体的策略选择和执行代码分割开来。
  • 修改上个Demo中的CashContext:
public class CashContext {

    private CashSuper mCash;

    public CashContext(String strategy) {
        switch (strategy) {
            case "正常收费":
                mCash = new CashNormal();
                break;
            case "满800减300":
                mCash = new CashSub(800,300);
                break;
            case "打8折":
                mCash = new CashDisc(0.8);
                break;
        }
    }

    public double getResult(double a) {
        return mCash.calCash(a);
    }

 }
  • 客户端代码:
public class CashMain {

    public static void main(String args[]) {
        CashContext context = new CashContext(args[0]);
//        switch (args[0]) {
//            case "正常收费":
//                context = new CashContext(new CashNormal());
//                break;
//            case "满800减300":
//                context = new CashContext(new CashSub(800,300));
//                break;
//            case "打8折":
//                context = new CashContext(new CashDisc(0.8));
//                break;
//        }
        if (context != null) {
            System.out.print("单价800的商品售价:" + context.getResult(800));
        }
    }

}

策略模式和工厂模式的对比

  • 工厂模式相当于黑盒子,我们并不关心产品是如何被创建出来的,只要给我这样产品就好。而策略模式相当于白盒子,你需要决定如何调用Context类中的策略。
  • 工厂模式主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。而策略模式为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。

策略模式的优缺点

  • 优点:
    • 策略模式封装了一系列算法,这些算法完成的都是相同的工作,只是实现不同,它可以用相同的方式去调用所有的算法,减少了各算法与使用算法的类之间的耦合。
    • 策略模式拥有不同的算法类,简化了单元测试。
    • 策略模式将不同的行为封装在一个个独立的Strategy类中,消除了条件语句。(如果全部行为放在一个类,肯定需要用if else语句判断使用的行为)
  • 缺点:
    • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。
    • 增加新的策略类还是需要改变客户端中的switch分支条件。

你可能感兴趣的:(策略模式)