一、概念
- 策略模式(Strategy Pattern)又叫政策模式(Policy Pattern),属于行为型模式。
- 通过面向对象的继承和多态机制,从而实现同一行为在不同场景下具备不同实现。
二、策略模式的生活场景
- 个人的交税率与他的工资有关。
- 支付方式的选择,微信支付,支付宝支付,银联支付。
三、适用场景
- 针对同一类型问题,有多种处理方式,每一种都能独立解决问题;
- 算法需要自由切换的场景;
- 需要屏蔽算法规则的场景。
三、角色构成
上下文角色(Context): 用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;
抽象策略角色(Strategy): 规定策略或算法的行为
具体策略角色(ConcreteStrategy): 具体的策略或算法实现
四、业务场景示例
优惠活动
- 创建促销粗略对象PromotionStrategy
/**
* <p>
* 促销策略对象
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-11-16
*/
public interface IPromotionStrategy {
/**
* 执行促销操作
*/
void doPromotion();
}
- 创建优惠券抵扣策略对象
/**
* <p>
* 优惠券策略
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-11-16
*/
public class CouponStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("使用优惠券抵扣");
}
}
- 创建返现促销策略对象CashbackStrategy
/**
* <p>
* 返现策略
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-11-16
*/
public class CashbackStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("返现,直接打款到支付宝帐号");
}
}
- 创建拼团优惠策略对象
/**
* <p>
* 团购策略
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-11-16
*/
public class GroupbuyStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("5人成团,可以优惠");
}
}
- 无优惠策略对象
/**
* <p>
* 无优惠
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-11-16
*/
public class EmptyStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("无优惠");
}
}
- 创建促销活动方案
/**
* <p>
* 促销活动方案
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-11-16
*/
public class PromotionActivity {
private IPromotionStrategy promotionStrategy;
@SuppressWarnings("all")
public PromotionActivity(IPromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
}
/**
* 执行促销策略
*/
public void executePromotionStrategy() {
promotionStrategy.doPromotion();
}
}
- 编写客户端测试类
public class Test {
public static void main(String[] args) {
PromotionActivity promotionActivity=null;
// 获取促销策略
String promotionKey= "COUPON";
if(StringUtils.equals(promotionKey,"COUPON")){
promotionActivity=new PromotionActivity(new CouponStrategy());
}else if(StringUtils.equals(promotionKey,"CASHBACK")){
promotionActivity=new PromotionActivity(new CashbackStrategy());
}//....
promotionActivity.executePromotionStrategy();
}
}
此客户端弊端在于if else太多了,随着业务的扩展只会越来越臃肿,所以需要改造。
- 创建促销策略工厂类
public class PromotionStrategyFactory {
public static Map<String,IPromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
static {
PROMOTION_STRATEGY_MAP.put(PromotionKey.EMPTY,new EmptyStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.COUPON,new CouponStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.CASHBACK,new CashbackStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.GROUPBUY,new GroupbuyStrategy());
}
public interface PromotionKey{
String EMPTY = "EMPTY";
String COUPON = "COUPON";
String CASHBACK = "CASHBACK";
String GROUPBUY = "GROUPBUY";
}
/**
* 获取促销策略的键集合
*
* @return 促销策略的键集合
*/
public static Set<String> getPromotionStrategyKeys(){
return PROMOTION_STRATEGY_MAP.keySet();
}
/**
* 根据促销码获取促销策略
* @param promotionKey 促销码
* @return 促销策略
*/
public static IPromotionStrategy getPromotionStrategy(String promotionKey){
return PROMOTION_STRATEGY_MAP.get(promotionKey);
}
}
- 改写客户端
public class Test {
public static void main(String[] args) {
// 获取促销策略
String promotionKey= "COUPON";
IPromotionStrategy promotionStrategy = PromotionStrategyFactory.getPromotionStrategy(promotionKey);
promotionStrategy.doPromotion();
}
}
总结
优点
- 策略模式符合开闭原则
- 避免使用多重条件转移语句,如if…else…语句,switch语句
- 使用策略模式可以提高算法的保密性和安全性。
缺点
- 客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
- 代码中会产生非常多策略类,增加维护难度。