设计模式之策略模式

扶醉桌前 提交于 2020-03-09 03:07:24

定义

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

if…else…

类型

行为型

适用场景

①、系统有很多类,而它们的区别仅仅在于它们的行为不同。
②、一个系统需要动态地在几种算法中选择一种。

优缺点

优点:
①、开闭原则
②、避免使用多重条件转移语句
③、提高算法的保密性和安全性

缺点:
①、客户端必须知道所有的策略类,并自行决定使用哪一个策略类
②、 产生很多策略类

代码实现

案例:电商网站经常会在不同的节日搞不同的促销活动,例如:满减、立减、返现等等。根据这个场景来使用策略模式实现。
首先创建一个促销策略的接口

public interface PromotionStrategy {

    /**
     * 促销
     */
    void doPromotion();
}

然后,分别创建不同促销策略的实现类。
返现促销

public class FanXianPromotionStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("返现促销,返回的金额存放到用户的余额中");
    }
}

立减促销

public class LiJianPromotionStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("立减促销,课程的价格直接减去配置的价格");
    }
}

满减促销

public class ManJianPromotionStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("满减促销,满100减50");
    }
}

无促销活动

public class EmptyPromotionStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("无促销策略");
    }
}

促销策略有了,还需要创建具体的促销活动

public class PromotionActivity {

    private PromotionStrategy promotionStrategy;

    public PromotionActivity(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }

    public void execute() {
        promotionStrategy.doPromotion();
    }
}

创建测试类

public class MainTest {

    public static void main(String[] args) {

        PromotionActivity promotionActivity = null;
        // 前台传过来的标志
        String PromotionKey = "LiJian";

        if (StringUtils.equals(PromotionKey, "LiJian")) {
            // 京东618立减
            promotionActivity = new PromotionActivity(new LiJianPromotionStrategy());
        } else if (StringUtils.equals(PromotionKey, "ManJian")) {
            // 双11 满减
            promotionActivity = new PromotionActivity(new ManJianPromotionStrategy());
        } else {
            promotionActivity = new PromotionActivity(new EmptyPromotionStrategy());
        }
        promotionActivity.execute();
    }
}

输出结果:

C:\android\java\jdk1.8\bin\java.exe
立减促销,课程的价格直接减去配置的价格

基本上策略模式就实现了,但是查看上面的代码,在开放立减策略或者其他策略的时候,都需要重新new一个当前的策略,这并不是我们所需要的。为了消除if…else…以及避免多次重复的创建对象,结合工厂设计模式对当前的代码进行改进。
首先创建一个策略工厂

public class PromotionStrategyFactory {

    /**
     * 存放所有促销策略
     */
    private static final Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
    /**
     * 没有促销
     */
    private static final EmptyPromotionStrategy EMPTY_PROMOTION_STRATEGY = new EmptyPromotionStrategy();

    private interface PromotionKey {
        String LIJian = "LiJian";
        String FanXian = "FanXian";
        String ManJian = "ManJian";
    }

    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.FanXian, new FanXianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJian, new LiJianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.ManJian, new ManJianPromotionStrategy());
    }

    private PromotionStrategyFactory() {
    }

    public static PromotionStrategy getPromotionStrategy(String PromotionKey) {
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(PromotionKey);
        return promotionStrategy == null ? EMPTY_PROMOTION_STRATEGY : promotionStrategy;
    }
}

这里使用Map来存放所有的促销策略,并在应用初始化时,就将策略放入Map集合中,并提供获取策略的方法。
编写测试类

    @Test
    public void testMethod2(){
        // 前台传过来的标志
        String PromotionKey = "ManJian";
        PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(PromotionKey));
        promotionActivity.execute();
    }

输出结果:

C:\android\java\jdk1.8\bin\java.exe 
满减促销,满100减50

这样就将if…else…消除了,并且简化了代码,使得代码的业务逻辑变得优雅。

相关源码

1. Jdk中的Comparator比较器。
2. Spring中的org.springframework.core.io.Resource。
3. Spring中bean初始化使用的InstantiationStrategy。

参考链接
https://coding.imooc.com/learn/list/270.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!