疑问一:什么是策略模式

先看看大佬们怎末说

策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具体行为的实现。策略模式最大的特点是行为的变化,行为之间可以相互替换。每个if判断都可以理解为就是一个策略。本模式使得算法可独立于使用它的用户而变化

策略模式是顾名思义就是指对象具有某个行为,但是在不同的业务场景下,这个行为应该有不同的表现形式,也就是有了不同的策略。让对象能再不同的场景下对同一行为有不同的实现,这就是策略模式。

策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数.

我自己浅薄的理解
策略就是,我想达到某件事,但是会面对不同的环境,所以要对每个环境提出针对性的策略, 来达到我的目的。
具体的代码实现的逻辑:
定义一个接口 把所有的策略实现都抽象出来
然后根据不同的业务场景对这个接口进下多实现
这个时候我们就可以用到多态
通过接口提供统一的方法 指向不同的决策实现类

疑问二:策略模式运用场景

先看看大佬们怎末说

登录类型,支付类型,供应商渠道,不同等级会员享受的优惠券价格不一样,等等业务判断,大量if else导致拓展(侧重新增)极其困难,维护(侧重修改)自然是改起来头痛(其实一个类型的增加[拓展一个类型]往往对应这个类型的增删改查CRUD[维护]),比如业务一开始一个简单的登录,往往做一个电话号码和验证码登录的方式或者账号密码登录方式,后来随着业务的增加或者提高用户体验,那么需要拓展(新增一种)三方登录,比如新增微信登录,支付宝登录,甚至抖音登录,一大堆,你要根据登录方式来处理,那就有点恼火吧,支付方式也是同样的问题,我们可以发现一个规律,凡是可以枚举的业务,往往都需要使用设计模式才能更好的解决,比如策略模式(往往搭配工厂模式使用更配哦),水来土掩,兵来将挡,这思想和高中数学中的分类讨论思想一模一样.遇事不要慌,因为还有dang中央.所以,我们就打个栗子,举个比方,更加形象一点

上面的举例很生动我们再业务中可能登录会有很多第三方登录方式和支付类型 这个情况用if else 代码会又臭又长 以后维护起来肯定比较麻烦

想了下 其实在很多项目中好像也又用到策略模式的 只是那时不知道策略模式是啥
实际项目运用一:日志记录
比如之前写的这篇文章
https://blog.csdn.net/QJY1437758743/article/details/128269835?spm=1001.2014.3001.5501

简单描述下
上面文章是实现了一个切面日志记录的功能,
但是有这么一种业务场景,就是可能他入参或者结果是不同的DTO,
而且可能字段属性还不一样,但是你要获取不同DTO指定的不同属性,
显然这个你去切面里面用 if 去判断DTO的类型 然后来获取字段属性,
这样是很糟糕的

所有可以把这样转换的方法 抽象出来写个接口 参数进行泛化
然后根据参数类型进行多实现 每个DTO 建一个转换的实现类
传不同的参数就可以实现不同的转换逻辑
很好的解耦和实现了开闭原则 这也是策略模式的一种表现嘛

实际项目运用二:jasper报表的数据源接口
公司真实项目代码就不贴出来了
业务逻辑:
我们会有很多报表 提供相应的 插入 查询等接口
可以先定义一个抽象类接口 定义相关好方法
然后每个报表的去实现这个接口和方法
这时候我们前端会把数据库配置的 bean名称 传给我们
我们拿到实现类的bean名称就可以获取到bean对象,从而调用对应报表的实现类方法

因为每个报表的数据组装代码里还是挺多的 所以主要的好处是 每张报表的实现都写在一个类里面 而且这里很好的利用了多态

疑问三:具体实现案例

案例来自:
文章:
https://blog.csdn.net/wozniakzhang/article/details/90526668
代码地址:
https://gitee.com/zhang-xiao-xiang/zxx-pattern/tree/master/src/main/java/com/zhang/zxx/pattern/strategy/


看代码前需要清楚
Spring之BeanPostProcessor(后置处理器)介绍
代码很简单就是通过实现BeanPostProcessor接口 在对象初始化之前 把类型key和bean对象放到map里面 然后根据传入的类型key获取指定实现类bean对象,最后执行策略方法。
1.Controller层

@Slf4j
@RestController
@RequestMapping("/strategy")
@RequiredArgsConstructor
public class StrategyController extends BaseController {@Resourceprivate BusinessService businessService;@GetMapping("/{key}")public Object doLoginWithOutStrategy(@PathVariable("key") Integer key) {// 这里顺带使用REST 风格接口 没有处理异常的和校验这些,因为这里重点是展示策略模式log.info("未使用策略模式控制层");return businessService.doLoginWithOutStrategy(key);}@GetMapping("/v2/{key}")public Object doLoginWithStrategy(@PathVariable("key") Integer key) {log.info("******使用策略模式控制层******");return businessService.doLoginWithStrategy(key);}
}

2.Service层

/*** BusinessService:业务服务层*/
public interface BusinessService {/*** 未使用策略模式的登录** @param key 登录类型* @return 登录结果*/Object doLoginWithOutStrategy(Integer key);/*** 使用策略模式登录[请求参数和返回参数自己根据具体业务设计就行,这里只是就请求参数传个枚举key,返回参数返回个Object为例子哈]** @param key 枚举的key* @return 返回值[可以为void, 根据你的业务设计就行]*/Object doLoginWithStrategy(Integer key);
}
/*** BusinessServiceImpl:模拟业务遇到的实现类(控制层controller->service层->dao层)*/
@Service
@Slf4j
@RequiredArgsConstructor
public class BusinessServiceImpl implements BusinessService {@Resourceprivate StrategyHandler strategyhandler;@Overridepublic Object doLoginWithOutStrategy(Integer key) {if (Objects.equals(LoginEnum.ACCOUNT.getKey(), key)) {log.info("用户根据[账号密码登录],执行相关逻辑===>未使用策略模式");return "[账号密码登录]";} else if (Objects.equals(LoginEnum.QQ.getKey(), key)) {log.info("用户根据[QQ登录],执行相关逻辑===>未使用策略模式");return "[QQ登录]";} else if (Objects.equals(LoginEnum.WECHAT.getKey(), key)) {log.info("用户根据[微信登录],执行相关逻辑===>未使用策略模式");return "[微信登录]";} else {log.info("用户根据[默认登录策略],执行相关逻辑===>未使用策略模式");return "[默认登录策略]";}}@Overridepublic Object doLoginWithStrategy(Integer key) {// 满足开闭原则,这里不管新增登录类型key还是修改类型key内部逻辑,这里都不需动,也不需要动它,闭就是禁止在这里修改,维护就很棒了return strategyhandler.handler(key);}
}

3.策略实现类

/*** AccountStrategyImpl:账户登录** @author zhangxiaoxiang* @date 2021/07/18*/
@Slf4j
@Service
public class AccountStrategyImpl implements StrategyService {@Overridepublic Integer matchKey() {return LoginEnum.ACCOUNT.getKey();}@Overridepublic Object handler(Integer key) {log.info("用户根据[账号密码登录],执行相关逻辑");return "[账号密码登录]";}}
/*** DefaultStrategyImpl:默认策略(相当于没有匹配请求参数返回的默认策略),一般策略模式都会带上默认策略,类似if else最后都有个else 或者switch语句的默认分支*/
@Service
@Slf4j
public class DefaultStrategyImpl implements StrategyService {@Overridepublic Integer matchKey() {return LoginEnum.DEFAULT.getKey();}@Overridepublic Object handler(Integer key) {log.info("用户根据[默认登录策略],执行相关逻辑");return "[默认登录策略]";}
}
/*** QQLoginStrategyImpl:QQ登录*/
@Slf4j
@Service
public class QQLoginStrategyImpl implements StrategyService {@Overridepublic Integer matchKey() {return LoginEnum.QQ.getKey();}@Overridepublic Object handler(Integer key) {log.info("用户根据[QQ登录],执行相关逻辑");return "[QQ登录]";}
}
/*** WechatStrategyImpl:微信登录逻辑*/
@Slf4j
@Service
public class WechatStrategyImpl implements StrategyService {@Overridepublic Integer matchKey() {return LoginEnum.WECHAT.getKey();}@Overridepublic Object handler(Integer key) {log.info("用户根据[微信登录],执行相关逻辑");return "[微信登录]";}
}

4.类型枚举类

/*** MyEnum:登录类型枚举[其它业务 比如支付类型,物流类型,运营商类型类比即可]*/
@AllArgsConstructor
public enum LoginEnum {/*** 账号*/ACCOUNT(1, "账号登录"),/*** QQ登录*/QQ(2, "QQ登录"),/*** 微信登录*/WECHAT(3, "微信登录"),/*** 暂不支持登录方式*/DEFAULT(0, "暂不支持登录方式");/*** 标识key*/@Getter@Setterprivate Integer key;/*** 标识value值*/@Getter@Setterprivate String value;
}

4.核心策略处理类

/*** StrategyHandler:策略处理类[可以理解为策略工厂类],Map<Integer, StrategyService>也可以使用private static final 修饰*/
@Component
@Slf4j
public class StrategyHandler implements BeanPostProcessor {Map<Integer, StrategyService> handlers = new ConcurrentHashMap<>();public Object handler(Integer key) {// 如果没有找到正常业务策略实现类处理方式1:写一个默认策略,比如HANDLERS.get(0)表示找到默认策略[兜底保留策略]Object result = Optional.ofNullable(handlers.get(key)).orElse(handlers.get(LoginEnum.DEFAULT.getKey())).handler(key);// 如果没有找到正常业务策略实现类处理方式2:直接抛业务异常,调用方处理,两种方式根据业务情况自行选择就行// Object result = Optional.ofNullable(HANDLERS.get(type)).orElseThrow(() -> new RuntimeException("未找到定义的策略实现类[抛出的业务异常]")).handler(o);log.info("从容器获取到:key={},对应的StrategyService处理结果:{}", key, result);return result;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof StrategyService) {StrategyService service = (StrategyService) bean;handlers.put(service.matchKey(), service);}return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}
}

5.核心策略处理抽象接口

/*** 登录策略*/
public interface StrategyService {/*** 需要返回枚举的key,用于处理注册对应逻辑** @return 枚举的key*/Integer matchKey();/*** 执行具体策略,这里写业务代码[拓展一种登录模式,只需要新增一个一个枚举值和对应的实现类就行]** @param key 具有逻辑请求需要的参数* @return 具体逻辑执行完毕返回的参数*/Object handler(Integer key);
}

从初学者的角度一起谈谈设计模式之策略模式相关推荐

  1. 橘子学设计模式之策略模式

    策略模式 1.简介 俗话说:条条大路通罗马.在很多情况下,实现某个目标的途径不止一条,例如我们在外出 旅游时可以选择多种不同的出行方式,如骑自行车.坐汽车.坐火车或者坐飞机,可根据实 际情况(目的地. ...

  2. Java设计模式之策略模式与状态模式

    一.策略模式定义 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们之间可以相互替换,策略模式可以在不影响客户端的情况下发生变化. 好了,定义看看就完了,我知道你很烦看定义. 二.策 ...

  3. 换个姿势学设计模式:策略模式

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源:公众号「闻人的技术博客」 前言 前段时间,接到一个 ...

  4. 研磨设计模式之 策略模式--转

    http://www.uml.org.cn/sjms/201009092.asp 研磨设计模式之 策略模式   2010-09-09 作者:云飞龙行 来源:云飞龙行的blog   先感谢众多朋友的支持 ...

  5. 设计模式:策略模式(Strategy)

    定   义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...

  6. C++设计模式之策略模式(Strategy)

    Strategy策略模式 作用:定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. UML图: 代码实现 #include <iostream& ...

  7. python策略模式包含角色_详解Python设计模式之策略模式

    虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用.<设计模式:可复用面向对象软件的基础>一书中有 23 个模式,其中有 16 个在动态语言中"不见了,或者简 ...

  8. 一篇博客读懂设计模式之-----策略模式

    设计模式之策略模式 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的对象 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换. 主要解决:在有多种算法相似的情况下 ...

  9. 面向对象设计模式之策略模式

    面向对象设计模式之策略模式 1.策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户 2.抽象鸭子类,鸭子飞行行为在此处类似于算法族 1 package ...

最新文章

  1. python 发邮件-带附件-文本-html
  2. 关于 golang 代理设置的
  3. 2021年计算机专业工作规划,2021年小学电脑室工作计划
  4. 去百度,还是去创新工厂
  5. 5、Python函数
  6. 图像检索:基于形状特征的算法
  7. Linux Shell下”/dev/null 21“相关知识说明
  8. [转载] Knowledge Management and Enginnering——02 知识表示方法
  9. 前端详细设计文档怎么写_UI设计师简历应该怎么写?
  10. 第一章 python大数据分析概述
  11. 音视频开发入门基础及视频会议即时通讯开源技术选择
  12. win7怎么看计算机Mac地址,Win7怎么查看MAC地址?Win7查看MAC地址的两种方法
  13. 算力网络走向智能社会,云计算初心未改(一)
  14. 如何科学的建立自己的个人网站
  15. 虾皮台湾店标价是用台币吗?要如何定价?
  16. 软件工程实验:原型设计
  17. 百度文库文件等待下载
  18. 路的选择与人生的哲思──读《未选择的路》
  19. 基于YOLOv7的芯片表面缺陷检测系统(源码&教程)
  20. 项目管理软件dhtmlxGantt配置教程(一):指定列设置

热门文章

  1. 影视网站之发送阿里云推送邮件教程
  2. 一篇搞懂Java多线程运行机制
  3. Python爬虫403错误的解决方案
  4. 利用Python实现图像的二值化
  5. Windows下使用脚本文件删除指定文件
  6. springboot 配置 Validator 校验框架国际化 支持快速返回
  7. ESXI6.7升级到ESXI7.0
  8. 如何计算产生SPWM所需要的占空比
  9. 通达信交易接口api的基本定义
  10. matlab动手实现k均值聚类的图像分割