策略模式(Strategy Pattern)是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。

策略模式的应用场景

1、系统中有很多类,而他们的区别仅仅在于他们的行为不同。

2、一个系统需要动态地在几种算法中选择一种。

用策略模式实现选择支付方式的业务场景

策略模式在生活场景中也非常多。在互联网高速发展下,在线购物非常普遍,每次下单我们都要选择支付方式,这就是一个很好应用策略模式的场景。

策略模式可以解决在很多算法相似的情况下,使用if...else或者swith...case看起来非常复杂和臃肿。在日常开发中, 策略模式适用以下场景:

1、针对同一类型问题,有多种处理方式,每一种都能独立解决问题;

2、算法需要自由切换的场景;

3、需要屏蔽算法规则的场景。

策略模式通用的UML类图:

策略模式_java

从UML类图中,可以看到策略模式主要有三种角色:

上下文角色(Context):用来操作策略的上下文环境,屏蔽客户端对策略算法的直接访问,封装可能存在变化;

抽象策略角色(Strategy):规定策略或算法的行为;

具体策略角色(ConcreteStrategy):具体的策略或算法实现。

使用策略模式实现促销优惠的业务场景

大家都知道,现在网商商城经常有促销活动,例如618,1111等。优惠策略可能有很多种:领取优惠券抵扣、返现促销、拼团优惠。下面我们用代码实现:

创建一个促销策略的抽象类:PromotionStrategy




public interface PromotionStrategy {  void doPromotion();}

创建优惠券抵扣策略类CouponStrategy、返现促销策略类CashbackStrategy、拼团优惠策略类GroupbuyStrategy和无优惠类




public class CouponStrategy implements PromotionStrategy {  @Override  public void doPromotion() {    System.out.println("使用优惠券折扣");  }}



public class CashbackStrategy implements PromotionStrategy {  @Override  public void doPromotion() {    System.out.println("使用促销返现");  }}



public class GroupbuyStrategy implements PromotionStrategy {  @Override  public void doPromotion() {    System.out.println("拼团");  }}



public class EmptyStrategy implements PromotionStrategy {  @Override  public void doPromotion() {    System.out.println("无优惠");  }}

测试类:



public class Test {  public static void main(String[] args) {    PromotionContext promotionContext1 = new PromotionContext(new CouponStrategy());    PromotionContext promotionContext2 = new PromotionContext(new CashbackStrategy());
   promotionContext1.execute();    promotionContext2.execute();
 }}

大家可能会发现,上面的测试类需要知道用到那个具体的策略类,一般可能会根据不同的需求对促销策略进行动态选择,并不会一次选择多个优惠,所以一般代码如下:




PromotionContext promotionContext = null;String promotionType = "COUPON";if(StringUtils.equals(promotionType,"COUPON")){    promotionContext =  new PromotionContext(new CouponStrategy()); }else if(StringUtils.equals(promotionType,"CASHBACK")){    promotionContext = new PromotionContext(new CashbackStrategy());}//... 其余代码省略promotionContext.execute();

经过改造之后,客户可以根据自己的需求进行不同选择优惠策略了。但是促销活动可能会越来越多,那么这些代码要频繁修改,违背了开闭原则,那我们可不可以结合其他设计模式呢?答案是肯定的,我们可以结合单例模式和工厂模式。

创建PromotionStrategyFactory类:





public class PromotionStrategyFactory {  private static Map<String,PromotionStrategy> PROMOTIONS = new HashMap<>();
 static {    PROMOTIONS.put(PromotionTypeEnum.COUPON.getValue(),new CouponStrategy());    PROMOTIONS.put(PromotionTypeEnum.GROUPBUY.getValue(),new GroupbuyStrategy());    PROMOTIONS.put(PromotionTypeEnum.CASHBACK.getValue(),new CashbackStrategy());  }
 private static final PromotionStrategy EMPTY = new EmptyStrategy();
 private PromotionStrategyFactory() {  }
 public static PromotionStrategy getPromotionStrategy(String promotionKey){    PromotionStrategy strategy = PROMOTIONS.get(promotionKey);    return strategy == null ? EMPTY : strategy;  }
}





public enum  PromotionTypeEnum {
 COUPON("COUPON"),  GROUPBUY("GROUPBUY"),  CASHBACK("CASHBACK"),  EMPTY("EMPTY"),  ;
 private String value;   PromotionTypeEnum(String value) {    this.value = value;  }
 public String getValue() {    return value;  }}

测试类:






public static void main(String[] args) {    String promotionKey = "CASHBACK";    PromotionStrategy promotionStrategy =   PromotionStrategyFactory.getPromotionStrategy(promotionKey);    promotionStrategy.doPromotion();}

策略模式的优缺点

优点:

1、策略模式服务符合开闭原则。

2、避免使用if...else语句,switch语句。

3、策略模式可以提高算法的保密性和安全性。

缺点:

1、客户端必须知道所有的策略,并且要自行决定使用哪一个策略。

2、代码中策略类会非常多,增加了维护成本。