前言
⚓ 渔夫出海前 并不知道鱼在哪
但还是会选择出海,因为相信会满载而归,很多时间,选择了才有机会,相信了才有可能。大胆的迈出想走的那一步吧,只要一直奔赴在路上,就终究会看到一片只为你而盛开的花海。
一、入门
1.1 概述

策略模式在古代中又称“计策”,简称“计”,如《汉书·高帝纪上》:“汉王从其计”。
而在现代,类似于每次向领导汇报的方案 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)类:持有一个策略类的引用,最终给客户端调用。
二、入门案例实战
对上面说的案例进行入门实战。
抽象策略类:
publicinterfaceMyStrategy {
publicvoidsay();
}
复制代码
具体策略类:
publicclassStrategyAimplementsMyStrategy{
@Override
publicvoidsay() {
System.out.println("you are my father !");
System.out.println("=====");
}
}
publicclassStrategyBimplementsMyStrategy{
@Override
publicvoidsay() {
System.out.println("和平共处!");
System.out.println("=====");
}
}
publicclassStrategyCimplementsMyStrategy{
@Override
publicvoidsay() {
System.out.println("you are my son !!!");
System.out.println("=====");
}
}
复制代码
环境类:
publicclassMyContext {
private MyStrategy strategy;
publicMyContext(MyStrategy strategy){
this.strategy = strategy;
}
publicvoidexec(){
strategy.say();
}
}
复制代码
测试类:
publicclassTestClient {
publicstaticvoidmain(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();
}
}
复制代码
输出结果:

三、工厂模式+策略模式实战
策略模式有个缺点,就是每次都需要 new 一个策略类来实现,可以结合工厂模式帮我们创建策略类,另外并未完全消除 if-else,使用工厂模式可以让代码变得更为清晰,只需根据传入的 code 调用工厂进行执行对应的策略即可。
策略接口
publicinterfaceMsgStrategy {
voidsendMsg();
}
复制代码
值班消息
publicclassMsgOneimplementsMsgStrategy{
@OverridepublicvoidsendMsg() {
System.out.println("发送值班消息!");
}
}
复制代码
如果是SpringBoot项目,策略类可以这样写,让策略类自动注册到工厂中,
工厂类里面就无需用静态代码库来生成策略产品
/*
@ServicepublicclassMsgOne implements Strategy, InitializingBean {
@Overridepublic void sendMsg() {
System.out.println("发送值班消息");
}
@Overridepublic void afterPropertiesSet() throws Exception {
Factory.register(StrategyEnum.CONCRETESTRATEGY1.getStrategyName(), this);
}
}
*/
复制代码
消息变更通知
publicclassMsgThreeimplementsMsgStrategy{
@OverridepublicvoidsendMsg() {
System.out.println("发送消息变更提醒");
}
}
复制代码
模板消息枚举类
/**
* 模板消息枚举类
* @Authorxiaolei
* @Date 2023/2/17 10:28
**/publicenumMsgEnum {
MSG_STRATEGY_1(101,"值班提醒"),
MSG_STRATEGY_2(201,"巡检提醒"),
MSG_STRATEGY_3(301,"信息变更通知")
;
privateInteger code;
privateString msgType;
MsgEnum(Integer code,String msgType){
this.code = code;
this.msgType = msgType;
}
publicIntegergetCode(){
returnthis.code;
}
publicStringgetMsgType(){
returnthis.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);
}
}
复制代码
测试类
publicclassMainTest {
publicstaticvoidmain(String[] args){
int code = 101;
MsgStrategy strategy = MsgFactory.getStrategy(code);
strategy.sendMsg();
}
}
复制代码
四、总结
优点
策略类之间可以自由切换,由于策略类都实现同一个接口,所以使它们之间可以自由切换。
易于扩展:增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合”开闭原则“
避免使用多重条件选择语句,充分体现面向对象设计思想
🍔总结:在开发中,凡是有同类型类似的算法需求,可以尝试使用策略模式进行封装来应对不同的变化。
作者:潇雷