likes
comments
collection
share

【浅谈设计模式】(14): 策略模式--臣有上中下三策,可来一看?

作者站长头像
站长
· 阅读数 13

前言

渔夫出海前 并不知道鱼在哪

但还是会选择出海,因为相信会满载而归,很多时间,选择了才有机会,相信了才有可能。大胆的迈出想走的那一步吧,只要一直奔赴在路上,就终究会看到一片只为你而盛开的花海。

一、入门

1.1 概述

【浅谈设计模式】(14): 策略模式--臣有上中下三策,可来一看?

策略模式在古代中又称“计策”,简称“计”,如《汉书·高帝纪上》:“汉王从其计”。

而在现代,类似于每次向领导汇报的方案 A、方案B、方案C 等,然后具体采用哪个,由领导自己定夺。

这就是策略模式,理解起来比较 easy 了。

策略模式:,它通过对算法进行封装,把使用算法的责任算法的实现分割开来,并委派给不同的对象对这些算法进行管理。。指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

那它主要解决什么问题呢

以古代战争为例

  • 情况1:如果对方人数远小于我方,则兵戎相见
  • 情况2:如果对方人数与我方相当,则和平发展
  • 情况3:如果对方人数远大于我方,则俯首称臣

这时候对应代码就是:

if( enemy < me ){
   System.out.println("you are my son");
}else if(enemy == me){
    System.out.println("和平发展");
}else if(enemy > me) {
    System.out.println("you are my father");
}

而使用策略模式,它能够解决,if else 所带来的复杂和难以维护,也就是一坨坨的 if-else 太多了太难看了,大佬发明了这种模式,让我们的代码能更优雅点。

1.2 结构

策略模式的主要角色如下:

  • 抽象策略类(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略类(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境类(Context)类:持有一个策略类的引用,最终给客户端调用。

二、入门案例实战

对上面说的案例进行入门实战。

抽象策略类:

public interface MyStrategy {
    public void say();
}

具体策略类:

public class StrategyA implements MyStrategy{
    @Override
    public void say() {
        System.out.println("you are my father !");
        System.out.println("=====");
    }
}

public class StrategyB implements MyStrategy{
    @Override
    public void say() {
        System.out.println("和平共处!");
        System.out.println("=====");
    }
}

public class StrategyC implements MyStrategy{
    @Override
    public void say() {
        System.out.println("you are my son !!!");
        System.out.println("=====");
    }
}

环境类:

public class MyContext {
    private MyStrategy strategy;

    public MyContext(MyStrategy strategy){
        this.strategy = strategy;
    }

    public void exec(){
        strategy.say();
    }
}

测试类:

public class TestClient {
    public static void main(String[] args) {
        System.out.println("遇到比我强的:");new MyContext(new StrategyA()).exec();
        System.out.println("遇到跟我一样的:");new MyContext(new StrategyB()).exec();
        System.out.println("遇到比我菜的:");new MyContext(new StrategyC()).exec();
    }
}

输出结果:

【浅谈设计模式】(14): 策略模式--臣有上中下三策,可来一看?

三、工厂模式+策略模式实战

策略模式有个缺点,就是每次都需要 new 一个策略类来实现,可以结合工厂模式帮我们创建策略类,另外并未完全消除 if-else,使用工厂模式可以让代码变得更为清晰,只需根据传入的 code 调用工厂进行执行对应的策略即可。

策略接口

public interface MsgStrategy {
    void sendMsg();
}

值班消息

public class MsgOne implements MsgStrategy{

    @Override
    public void sendMsg() {
        System.out.println("发送值班消息!");
    }
}

如果是SpringBoot项目,策略类可以这样写,让策略类自动注册到工厂中,

工厂类里面就无需用静态代码库来生成策略产品

    /*
    @Service
    public class MsgOne implements Strategy, InitializingBean {
        @Override
        public void sendMsg() {
            System.out.println("发送值班消息");
        }
        @Override
        public void afterPropertiesSet() throws Exception {
            MsgFactory.register(MsgEnum.MSG_STRATEGY_1.getMsgType(), this);
        }
    }
    */

消息变更通知

public class MsgThree implements MsgStrategy{
    @Override
    public void sendMsg() {
        System.out.println("发送消息变更提醒");
    }
}

模板消息枚举类

/**
 * 模板消息枚举类
 * @Author xiaolei
 * @Date 2023/2/17 10:28
 **/
public enum MsgEnum {
    MSG_STRATEGY_1(101,"值班提醒"),
    MSG_STRATEGY_2(201,"巡检提醒"),
    MSG_STRATEGY_3(301,"信息变更通知")
    ;
    private Integer code;
    private String msgType;
    MsgEnum(Integer code,String msgType){
        this.code = code;
        this.msgType = msgType;
    }
    public Integer getCode(){
        return this.code;
    }
    public String getMsgType(){
        return this.msgType;
    }
}

工厂类

public class MsgFactory {
    private static Map<Integer,MsgStrategy> factory = new ConcurrentHashMap<>();
    /**
     * 生产策略消息
     */
    static {
        factory.put(MsgEnum.MSG_STRATEGY_1.getCode(),new MsgOne());
        factory.put(MsgEnum.MSG_STRATEGY_2.getCode(),new MsgTow());
        factory.put(MsgEnum.MSG_STRATEGY_3.getCode(),new MsgThree());
    }

    /**
     * 根据类型获取策略
     */
    public static MsgStrategy getStrategy(Integer code){
        return factory.get(code);
    }

    public static void setStrategy(Integer code,MsgStrategy msgStrategy){
        factory.put(code,msgStrategy);
    }

}

测试类

public class MainTest {
    public static void main(String[] args) {
        int code = 101;
        MsgStrategy strategy = MsgFactory.getStrategy(code);
        strategy.sendMsg();
    }
}

四、总结

优点

  • 策略类之间可以自由切换,由于策略类都实现同一个接口,所以使它们之间可以自由切换。
  • 易于扩展:增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合”开闭原则“
  • 避免使用多重条件选择语句,充分体现面向对象设计思想

🍔总结:在开发中,凡是有同类型类似的算法需求,可以尝试使用策略模式进行封装来应对不同的变化。