【浅谈设计模式】(14): 策略模式--臣有上中下三策,可来一看?
前言
⚓渔夫出海前 并不知道鱼在哪
但还是会选择出海,因为相信会满载而归,很多时间,选择了才有机会,相信了才有可能。大胆的迈出想走的那一步吧,只要一直奔赴在路上,就终究会看到一片只为你而盛开的花海。
一、入门
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)类:持有一个策略类的引用,最终给客户端调用。
二、入门案例实战
对上面说的案例进行入门实战。
抽象策略类:
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();
}
}
输出结果:
三、工厂模式+策略模式实战
策略模式有个缺点,就是每次都需要 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();
}
}
四、总结
优点
- 策略类之间可以自由切换,由于策略类都实现同一个接口,所以使它们之间可以自由切换。
- 易于扩展:增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合”开闭原则“
- 避免使用多重条件选择语句,充分体现面向对象设计思想
🍔总结:在开发中,凡是有同类型类似的算法需求,可以尝试使用策略模式进行封装来应对不同的变化。
转载自:https://juejin.cn/post/7203989487138144312