类型:行为型设计模式
核心思想:定义一系列算法或行为,将它们封装起来,使得它们可以互换。
针对场景:当需要为同一个行为提供不同的实现(如不同类型用户的定价策略、不同支付方式的选择等)实例如下:
- 电商平台的杀熟策略,针对不同活跃度用户,实现不同的定价策略。例如新用户优惠策略、忠诚用户策略、老用户高价策略等。
- 某多多的营销系统中,根据不同的用户行为(签到/平台下单)赋予用户不同的抽奖次数。
- 为完成订单支付这个目的,会有支付宝支付、微信支付、银行卡支付等多种实现方式。
在上面的场景中,简单的实现会产生大量的 if-else
语句,如果新增具体策略,需要修改原来的代码,不符合开闭原则。
基本结构
策略模式的主要结构为:具体策略、上下文、策略以及客户端。
- 策略是所有具体策略的共同接口或抽象类,声明需要实现的目的。
- 具体策略就是完成特定任务的各个差异化策略的类。
- 上下文类包含一个策略接口的引用,用于指向具体的策略对象。仅通过策略接口与具体策略类交互,而不直接与具体的实现类打交道(这样需要新增具体策略时,只需要增加新的策略实现类即可)。上下文类通常暴露一个设置策略的方法,使得客户端可以动态切换不同的策略。
- 客户端不直接用
if-else
选择使用的具体策略,而是将选择的具体策略实现类通过上下文类的设置器传递给上下文类,从而改变其行为(doSomething)。
优势
符合开闭原则
策略模式 v.s. 模版方法模式
模板方法模式基于继承机制: 它允许你通过扩展子类中的部分内容来改变部分算法。 策略基于组合机制: 你可以通过对相应行为提供不同的策略来改变对象的部分行为。
模板方法在类层次上运作, 因此它是静态的。 策略在对象层次上运作,因此允许在运行时切换行为,是动态的行为模式。
使用案例
在开发抽奖系统中,抽奖额度可以通过用户行为(签到等)返利获取,也可以通过积分兑换获取。这里就可以使用策略模式,对同一功能接口分别实现不同具体策略,在客户端中通过Spring自动装配的Map<String, ITradePolicy>来获取对应的策略。
// 策略接口
public interface ITradePolicy {
/**
* 策略模式总接口方法 sku订单交易
* @param createQuotaOrderAggregate
*/
void trade(CreateQuotaOrderAggregate createQuotaOrderAggregate);
}
// 具体策略A
@Service("rebate_no_pay_trade")
public class RebateNoPayTradePolicy implements ITradePolicy {
@Resource
private IActivityRepository repository;
@Override
public void trade(CreateQuotaOrderAggregate createQuotaOrderAggregate) {
createQuotaOrderAggregate.setOrderState(ActivityOrderStateVO.completed);
createQuotaOrderAggregate.setPayAmount(BigDecimal.ZERO);
repository.doSaveNoPayOrder(createQuotaOrderAggregate);
}
}
// 具体策略B
@Service("credit_pay_trade")
public class CreditPayTradePolicy implements ITradePolicy {
@Resource
private IActivityRepository repository;
@Override
public void trade(CreateQuotaOrderAggregate createQuotaOrderAggregate) {
createQuotaOrderAggregate.setOrderState(ActivityOrderStateVO.wait_pay);
repository.doSaveCreditPayOrder(createQuotaOrderAggregate);
}
}
// 客户端
public abstract class AbstractRaffleActivityAccountQuota extends RaffleActivityAccountQuotaSupport implements IRaffleActivityAccountQuotaService {
private final Map<String, ITradePolicy> tradePolicyGroup;
public AbstractRaffleActivityAccountQuota(IActivityRepository repository, DefaultActivityChainFactory defaultActivityChainFactory, Map<String, ITradePolicy> tradePolicyGroup) {
super(repository, defaultActivityChainFactory);
this.tradePolicyGroup = tradePolicyGroup;
}
@Override
public String createOrder(SkuRechargeEntity skuRechargeEntity) {
// ... ... 上述代码略... ...
// 5. 实际落库操作 此处用策略模式实现不同的落库方式(行为返利:直接增加额度 积分交易:需要扣减积分)
ITradePolicy tradePolicy = tradePolicyGroup.get(skuRechargeEntity.getOrderTradeType().getCode());
tradePolicy.trade(createQuotaOrderAggregate);
}