策略模式(Strategy Pattern)是指定义了算法家族、分别封装后,让他们相互之间可以互相替换,次模式让算法的变化不会影响到使用算法的用户。
策略模式的结构
- 封装类:也叫上下文,对策略进行二次封装,目的是避免高层模块对策略的直接调用。
- 抽象策略:通常情况下为一个接口,当各个实现类中存在着重复的逻辑时,则使用抽象类来封装这部分公共的代码,此时,策略模式看上去更像是模版方法模式。
- 具体策略:具体策略角色通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。
策略模式的适用场景
- 系统中存在很多类,而他们区别仅仅在于他们的行为不同。
- 系统需要动态的在集中算法中选择一种。
使用策略模式实现支付方式
大家在网购中经常会碰到优惠活动,有使用优惠券或满199-100返现活动等,而这些不一样的优惠方式就可以用上策略模式。
首先,我们定义一个促销优惠的抽象类PromotionStrategy
,在其中定义一个促销方法,让所有具体的策略都继承这个类。
public interface PromotionStrategy {
void doPromotion();
}
之后使用优惠券(CouponStrategy())和返现(CashbackStrategy())作为促销的实现类
public class CouponStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("优惠券抵扣策略");
}
}
public class CashbackStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("返现策略");
}
}
最后,定义一个策略的封装类PromotionActivity
public class PromotionActivity {
private PromotionStrategy promotionStrategy;
public PromotionActivity(PromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
}
public void execute(){
promotionStrategy.doPromotion();
}
}
这样我们就可以测试一下效果,通过传入不同策略来运行。
public static void main(String[] args) {
PromotionActivity promotionActivity = null;
String promotionKey = "coupon";
if (promotionKey.equals("coupon")){
promotionActivity = new PromotionActivity(new CouponStrategy()) ;
}else if (promotionKey.equals("cashback")){
promotionActivity = new PromotionActivity(new CashbackStrategy()) ;
}
promotionActivity.execute();
}
这样我们可以通过不同的需要来选择不同的优惠策略。但是,经过一段时间的业务积累,我们的促销活动越来越多,每次都要修改大量代码和测试,判断也变得越来越复杂。这时我们的代码就该重构了,我们通过之前学过的单例模式和工厂模式对代码进行改造。
下面我们加入一个促销工厂类PromotionStrategyFactory
,创建一个map来维护我们的促销策略,通过getPromotionStrategy(String promotionKey)
方法获取到具体的策略。
public class PromotionStrategyFactory {
private static Map<String,PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
static {
PROMOTION_STRATEGY_MAP.put("coupon",new CouponStrategy());
PROMOTION_STRATEGY_MAP.put("cashback",new CashbackStrategy());
}
private PromotionStrategyFactory(){}
public static PromotionStrategy getPromotionStrategy(String promotionKey){
PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
return promotionStrategy;
}
}
而这时,我们的测试类也应该修改一下了。
public class Test {
public static void main(String[] args) {
PromotionStrategy p = PromotionStrategyFactory.getPromotionStrategy("coupon");
PromotionActivity pa = new PromotionActivity(p);
pa.execute();
}
}
这样我们每次上新活动之后就不用影响之前代码的逻辑,只需在map中加入新促销活动即可。
策略模式的优缺点
优点:
- 策略模式符合开闭原则
- 避免使用大量判断语句
- 使用策略模式可以提高算法的保密性和安全性
缺点: - 客户端必须知道所有策略,并且自己觉得使用策略
- 代码产生很多策略类,增加维护难度