学习了一下策略模式,秉着好记性不如烂笔头的耿直,记录并分享给大家,望同学们一键三连!!!
直接进入主题:
策略模式的官方定义:
将定义的算法家族分别封装起来,让他们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户。
策略模式使用的就是面向对象的继承和多态机制,从而实现一个行为在不同场景下具备不同的实现。
策略模式的应用场景
1. 阶梯个税:不同的税率对应不用的处理方式
2. 支付方式的选择:不同的支付方式对应不同的渠道
策略模式可以解决在有多种相似算法的情况下使用if...else或者swith...case所带来的复杂性和臃肿性的问题,主要适用于:
(1)针对同一类型问题,有多种处理方式,每一种都能独立解决问题。
(2)需要自由切换算法的场景。
(3)需要屏蔽算法规则的场景。
UML类图
由上图可以看到,策略模式主要包含3部分
- 角色调度层:用来操作所需要的的上下文环境,屏蔽高层模块(客户端对策略、算法的直接访问),封装可能存在的变化
- 抽象策略角色(IPromotionStrategy):规定策略或算法的行为
- 具体的策略角色:具体的策略或者算法实现
最简单的策略模式写法
public class Client {
/**
* 抽象策略类
*/
interface IStrategy{
void algorithm();
}
static class ConCreateStrategyA implements IStrategy{
@Override
public void algorithm() {
System.out.println("Strategy A");
}
}
static class ConCreateStrategyB implements IStrategy{
@Override
public void algorithm() {
System.out.println("Strategy B");
}
}
/**
* 调度算法
*/
static class Context{
private final IStrategy strategy;
public Context(IStrategy iStrategy){
this.strategy = iStrategy;
}
public void algorithm(){
this.strategy.algorithm();
}
}
public static void main(String[] args) {
// 生成一个具体策略
IStrategy strategy = new ConCreateStrategyA();
// 创建一个环境
Context context = new Context(strategy);
// 执行算法
context.algorithm();
}
}
解决实现问题
一个方案的实现主要是为了解决实际中发生的问题,来看一个促销的例子.
场景:淘宝活动优惠打折,优惠策略有很多种可能,如领取优惠券抵扣、返现促销、拼团优惠等。
首先创建促销实例的抽象
/**
* 促销策略抽象
*/
public interface IPromotionStrategy {
void doPromotion();
}
然后分别创建具体的优惠方案
优惠券抵扣方案:
public class CouponStrategy implements IPromotionStrategy {
@Override
public void doPromotion() {
System.out.println("使用优惠券抵扣");
}
}
返现促销:
public class CashbackStrategy implements IPromotionStrategy {
@Override
public void doPromotion() {
System.out.println("返现,直接打款");
}
}
拼团优惠:
public class GroupbuyStrategy implements IPromotionStrategy {
@Override
public void doPromotion() {
System.out.println("5人成团,可以优惠");
}
}
无优惠:
public class EmptyStrategy implements IPromotionStrategy {
@Override
public void doPromotion() {
System.out.println("无优惠");
}
}
我们来创建一个实际的策略调度层
/**
* 促销活动方案
*/
public class PromotionActivity {
private final IPromotionStrategy iPromotionStrategy;
public PromotionActivity(IPromotionStrategy iPromotionStrategy){
this.iPromotionStrategy = iPromotionStrategy;
}
public void execute(){
iPromotionStrategy.doPromotion();
}
}
调度层代码就写好了,那整个策略模式的实现就基本上完成了,下面我们来看一下如何使用,看客户端的测试代码
PromotionActivity promotion = null;
String key = args[0];
if(Objects.equals(key, "COUPON")){
promotion = new PromotionActivity(new CouponStrategy());
}else if(Objects.equals(key, "CASHBACK")){
promotion = new PromotionActivity(new CashbackStrategy());
}
promotion.execute();
放到实际的业务场景中,完全能够满足业务场景,但是大家觉得有什么问题呢? 随着业务高速发展,各种优惠券铺天盖地的来,于是,程序员就开始经常加班,每次上活动之前都要通宵改代码,而且要做重复测试,判断逻辑可能也会变得越来越复杂。此时,我们要思考代码是否需要重构。我们来一起看下,利用单例和简单工厂模式,创建PromotionStrategyFactory类
public class PromotionStrategyFactory {
private static final IPromotionStrategy DEFAULT = new EmptyStrategy();
private static Map<String, IPromotionStrategy> PROMOTIONS = new HashMap<>();
static {
PROMOTIONS.put(PromotionKey.COUPON, new CouponStrategy());
PROMOTIONS.put(PromotionKey.CASHBACK, new CashbackStrategy());
PROMOTIONS.put(PromotionKey.GROUPBUY, new GroupbuyStrategy());
}
public static IPromotionStrategy getStrategy(String key){
IPromotionStrategy strategy = PROMOTIONS.get(key);
return strategy==null?DEFAULT:strategy;
}
private interface PromotionKey{
String COUPON = "COUPON";
String CASHBACK = "CASHBACK";
String GROUPBUY = "GROUPBUY";
}
}
完成后,我们再看客户端测试代码:
String promotionKey = args[0];
IPromotionStrategy strategy = PromotionStrategyFactory.getStrategy(promotionKey);
strategy.doPromotion();
这样就简洁了很多,也充分体现了我们使用设计模式的目的。最终程序员也不再加班了。
Attention
上面是利用了接口来实现的策略模式,大家的思维不要仅仅局限于implements接口,开篇就说过,策略模式使用的就是面向对象的继承和多态机制。这里就不再赘述,原理都是一样。
缺点
人无完人,每种设计模式也是在特定的场景下才能发挥出最佳的效果,滥用设计模式必将为以后的加班埋下祸根。那我们来看看策略模式的缺点:
- 客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
- 代码中会产生非常多策略类,增加维护难度。