定义:
策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。 比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。
优缺点:
优点:
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。
 - 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
 - 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
 - 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
 - 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
 
缺点:
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
 - 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。
 - 所有策略类都需要对外暴露。
 
使用场景:
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
 - 一个系统需要动态地在几种算法中选择一种。
 - 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现
 
实现:
1.定义一个接口
/**
 * 
 * @author pms
 *
 */
public interface Strategy {
   public int doOperation(int num1, int num2);
}
2.创建实现接口的实体类
/**
 * 具体策略类:加法
 * @author pms
 *
 */
public class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}
/**
 * 具体策略类:减法
 * @author pms
 *
 */
public class OperationSubtract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}
3.创建Context类
/**
 *环境类(Context)
 * @author pms
 *
 */
public class Context {
   private Strategy strategy;
 
   public Context(Strategy strategy){
      this.strategy = strategy;
   }
 
   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}
4.测试
public class Test(){
  Context context = new Context(new OperationAdd());
  System.out.println("222 + 111 = " + context.executeStrategy(222, 111));
  context = new Context(new OperationSubtract());
  System.out.println("222 - 111 = " + context.executeStrategy(222, 111));
}
运行结果:
222 + 111 = 333
222 - 111 = 111
应用(使用策略模式代替过多的if else)
假设我们要做一个外卖平台,有这样的需求:
- 外卖平台上的某家店铺为了促销,设置了多种会员优惠,其中包含超级会员折扣8折、普通会员折扣9折和普通用户没有折扣三种。
 - 希望用户在付款的时候,根据用户的会员等级,就可以知道用户符合哪种折扣策略,进而进行打折,计算出应付金额。
 - 随着业务发展,新的需求要求专属会员要在店铺下单金额大于30元的时候才可以享受优惠。
 - 接着,又有一个变态的需求,如果用户的超级会员已经到期了,并且到期时间在一周内,那么就对用户的单笔订单按照超级会员进行折扣,并在收银台进行强提醒,引导用户再次开通会员,而且折扣只进行一次。
 
那么,我们可以看到以下伪代码:
public BigDecimal calPrice(BigDecimal orderPrice, String buyerType) {
if (用户是专属会员) {
    if (订单金额大于30元) {
        returen 7折价格;
    }
}
if (用户是超级会员) {
    return 8折价格;
}
if (用户是普通会员) {
    if(该用户超级会员刚过期并且尚未使用过临时折扣){
        临时折扣使用次数更新();
        returen 8折价格;
    }
    return 9折价格;
}
return 原价;
}
这样的代码中,有很多if-else,并且还有很多的if-else的嵌套,无论是可读性还是可维护性都非常低。
那么,如何改善呢?
策略模式
接下来,我们尝试引入策略模式来提升代码的可维护性和可读性。
首先,定义一个接口:
/**
 * @author mhcoding
 */
public interface UserPayService {
    /**
     * 计算应付价格
     */
    public BigDecimal quote(BigDecimal orderPrice);
}
接着定义几个策略类:
/**
 * @author mhcoding
 */
public class ParticularlyVipPayService implements UserPayService {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
         if (消费金额大于30元) {
            return 7折价格;
        }
    }
}
public class SuperVipPayService implements UserPayService {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
        return 8折价格;
    }
}
public class VipPayService implements UserPayService {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
        if(该用户超级会员刚过期并且尚未使用过临时折扣){
            临时折扣使用次数更新();
            returen 8折价格;
        }
        return 9折价格;
    }
}
引入了策略之后,我们可以按照如下方式进行价格计算:
/**
 * @author mhcoding
 */
public class Test {
    public static void main(String[] args) {
        UserPayService strategy = new VipPayService();
        BigDecimal quote = strategy.quote(300);
        System.out.println("普通会员商品的最终价格为:" + quote.doubleValue());
        strategy = new SuperVipPayService();
        quote = strategy.quote(300);
        System.out.println("超级会员商品的最终价格为:" + quote.doubleValue());
    }
}