基于Spring自动注入快速实现策略模式+工厂模式优化过多的if..else

一、策略模式

1.1策略模式定义

在策略模式(Strategy Pattern)中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

1.2 使用场景

1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

2、一个系统需要动态地在几种算法中选择一种。

3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

二、工厂模式

2.1工厂模式定义

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

2.2 使用场景

 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

三、实现

        需求为用户在美团上购买物品后的核销业务,根据不同核销完成后的返回结果进行核销限制添加积分等,例如是否是本公司app下的会员,是否添加本公司企微,是否关注本公司公众号来进行对应操作,(后续可能会添加其他核销方式),所以该处可利用策略模式实现,而不是一长串的if..else进行功能的实现,违反了开闭原则(对扩展开放,对修改封闭),

3.1 使用if...else实现功能伪代码

        过多嵌套,后续扩展功能不利于维护,实现简单

public class StrategyTest {@Resourceprivate TbUserDao tbUserDao;@Resourceprivate TbActivityDao tbActivityDao;@Resourceprivate MtCouponService mtCouponService;@Testpublic Object verify (String userId,String receipt_code) {Map<String,Object> result = new HashMap<>();//1. 获取用户信息TbUser tbUser = tbUserDao.selectUserByUserId(userId);if (null == tbUser) {return null;}// 根据receipt_code 和 skuId 查询出需要核销的类型// 2. 根据不同的核销类型进行核销String callBackMsg = mtCouponService.getCoinByReceiptCode(receipt_code, userId, "杭州");Map callBackMap = JSON.parseObject(callBackMsg, Map.class);if ("200".equals(callBackMap.get("code"))) {//2.1. 判断核销记录增加活动对应参数TbActivity activity = new TbActivity();activity.setModifyTime(new Date());if ("企微".equals(callBackMap.get("type"))) {activity.setActivitySource("企微");activity.setActivityCurrency(tbUser.getUserCurrency() + 200);tbActivityDao.insert(activity);result.put("code", "200");result.put("msg", "核销成功");return result;}else  if ("加入企微群".equals(callBackMap.get("type"))) {activity.setActivitySource("加群");activity.setActivityCurrency(tbUser.getUserCurrency() + 230);tbActivityDao.insert(activity);result.put("code", "200");result.put("msg", "核销成功");return result;}else  if ("关注公众号".equals(callBackMap.get("type"))) {activity.setActivitySource("关注公众号");activity.setActivityCurrency(tbUser.getUserCurrency() + 300);tbActivityDao.insert(activity);result.put("code", "200");result.put("msg", "核销成功");return result;}else  if ("开通会员".equals(callBackMap.get("type"))) {activity.setActivitySource("开通会员");activity.setActivityCurrency(tbUser.getUserCurrency() + 400);tbActivityDao.insert(activity);result.put("code", "200");result.put("msg", "核销成功");return result;}}result.put("code", "505");result.put("msg", callBackMap.get("msg"));return result;}
}

3.2 使用策略模式+工厂模式

        涉及到实际业务,服务实现直接简化为打印相应核销策略

抽象策略类接口

public interface VerificationService {String verificationName();void verify();
}

实现具体策略服务

@Service
public class OfficialAccountsServiceImpl implements  VerificationService{@Overridepublic String verificationName() {return VerificationEnum.OfficialAccounts.getName();}@Overridepublic void verify() {System.out.println("公众号核销 = ");}
}
@Service
public class VipVerificationServiceImpl implements  VerificationService{@Overridepublic String verificationName() {return VerificationEnum.Vip.getName();}@Overridepublic void verify() {System.out.println("会员核销 = ");}
}
@Service
public class WeComGroupServiceImpl implements  VerificationService{@Overridepublic String verificationName() {return VerificationEnum.WeComGroup.getName();}@Overridepublic void verify() {System.out.println("企微加群核销 = ");}
}
@Service
public class WeComVerificationServiceImpl implements  VerificationService{@Overridepublic String verificationName() {return VerificationEnum.WeCom.getName();}@Overridepublic void verify() {System.out.println("企微核销 = ");}
}

环境类

/***  核销枚举类*/
public enum VerificationEnum {WeCom( "WeCom"),WeComGroup("WeComGroup"),OfficialAccounts( "OfficialAccounts"),Vip("Vip");private String name;VerificationEnum(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
/***  初始化,并获取VerificationService所有服务bean*/
@Component
@Slf4j
public class StrategyHandler implements InitializingBean, ApplicationContextAware {/*** 存放策略的map,可以理解为策略的注册中心*/@Resourceprivate final Map<String, VerificationService> strategyServiceMap = new ConcurrentHashMap<>(16);/*** spring的上下文*/private ApplicationContext applicationContext;@Overridepublic void afterPropertiesSet() {//初始化把所有的策略bean放进ioc,使用的时候获取Map<String, VerificationService> matchBeans = applicationContext.getBeansOfType(VerificationService.class);//策略注入的bean做key,策略实现类做valuematchBeans.forEach((key, value) -> {strategyServiceMap.put(value.verificationName(), value);log.info("项目启动时初始化核销策略模式为: key={},value={}", key, value);});}/**** @param applicationContext    spring的上下文* @throws BeansException 获取bean异常*/@Overridepublic void setApplicationContext(@NotNull(message = "bean不能为空") ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}/*** 通过key获取对应的策略实现** @param verificationName key 核销名称  (String类型或者整形都行,保持和策略接口一致就行)* @return VerificationService 具体的核销服务*/public VerificationService  getStrategy(String verificationName) throws RuntimeException{if (null == strategyServiceMap.get(verificationName)) {//默认策略throw  new RuntimeException("核销策略异常...");}return strategyServiceMap.get(verificationName);}}

        *初始化项目时直接注册服务,方便调用 

        调用方便,易扩展,但是实现过程较繁琐,

public class StrategyTest {@Resourceprivate StrategyHandler strategyHandler;@Testpublic void test() {Map<String,Object> result = new HashMap<>();//1. 获取用户信息TbUser tbUser = tbUserDao.selectUserByUserId(userId);if (null == tbUser) {return null;}// 根据receipt_code 和 skuId 查询出需要核销的类型// 2. 根据不同的核销类型进行核销String callBackMsg = mtCouponService.getCoinByReceiptCode(receipt_code, userId, "杭州");Map callBackMap = JSON.parseObject(callBackMsg, Map.class);if ("200".equals(callBackMap.get("code"))) {//服务实现类里直接实现具体操作strategyHandler.getStrategy(callBackMap.get("type")).verify();    result.put("code", "200");result.put("msg", "核销成功");return result;}  result.put("code", "505");result.put("msg", callBackMap.get("msg"));return result; }

四 总结

4.1 优点

  • 提高了代码的复用性和可维护性,将算法的定义与其具体实现进行解耦。
  • 可以在运行时动态替换算法,提高了程序的灵活性。
  • 符合开闭原则,新增算法无需修改现有代码。

4.2 缺点

  • 客户端需要知道所有的策略类,并根据具体场景选择合适的策略,增加了客户端的复杂度。
  • 如果策略类较多,会导致类的数量增多,增加系统的复杂度。

4.3 适用场景

  • 当一个系统中存在多个类只有它们的行为或算法不同时。
  • 当一个类定义了多种行为,而这些行为在这个类的操作中以多个条件语句的形式出现,可以将相关的条件分支移入它们各自的策略类中,以替换这些条件语句。
  • 当系统需要动态地在几种算法中选择一种时,如根据不同的配置、用户选择或者环境条件等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/294487.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

echarts:设置折线图线条和端点的颜色

1、代码 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>Echarts折线图</title> </head> <body> <div id"main" style"width: 600px;height:400px;"></div> <sc…

爬虫概念简述

爬虫简述 ⼀、什么是爬虫&#xff1f;二、爬虫有什么用?三、爬虫的分类四、所谓的“爬虫学的好&#xff0c;牢饭吃到饱 !”五、爬虫的大致流程 ⼀、什么是爬虫&#xff1f; ​ 简言之&#xff0c;爬虫可以帮助我们把网站上的信息快速提取并保存下来。 ​ 我们可以把互联网比…

2016年第五届数学建模国际赛小美赛C题对超级细菌的战争解题全过程文档及程序

2016年第五届数学建模国际赛小美赛 C题 对超级细菌的战争 原题再现&#xff1a; 最近有很多关于我们抗生素耐药性危机的讨论。进化出的能够抵抗抗生素的细菌每年杀死70万人&#xff0c;越来越强大的细菌正在世界各地传播。研究人员担心&#xff0c;我们将进入一个后抗生素时代…

U-Net: Convolutional Networks for Biomedical Image Segmentation(CVPR2015)

文章目录 AbstractIntroductionNetwork ArchitectureConclusiontorch code hh 源代码 Abstract 人们普遍认为&#xff0c;深度网络的成功训练需要成千上万个带注释的训练样本。在这篇论文中&#xff0c;我们提出了一个网络和训练策略&#xff0c;该策略依赖于数据增强的强大使…

红队打靶练习:DIGITALWORLD.LOCAL: MERCY V2

目录 信息收集 1、arp 2、netdiscover 3、nmap 4、nikto 5、whatweb 6、总结 目录探测 1、gobuster 2、dirsearch WEB enum4linux枚举工具 smbclient工具 knock工具 CMS 文件包含漏洞 Tomcat 提权 系统信息收集 本地提权 get root 信息收集 1、arp ┌──…

redis 从0到1完整学习 (六):Hash 表数据结构

文章目录 1. 引言2. redis 源码下载3. dict 数据结构4. 哈希表扩容与 rehash5. 参考 1. 引言 前情提要&#xff1a; 《redis 从0到1完整学习 &#xff08;一&#xff09;&#xff1a;安装&初识 redis》 《redis 从0到1完整学习 &#xff08;二&#xff09;&#xff1a;red…

HarmonyOS4.0系统性深入开发01应用模型的构成要素

应用模型的构成要素 应用模型是HarmonyOS为开发者提供的应用程序所需能力的抽象提炼&#xff0c;它提供了应用程序必备的组件和运行机制。有了应用模型&#xff0c;开发者可以基于一套统一的模型进行应用开发&#xff0c;使应用开发更简单、高效。 HarmonyOS应用模型的构成要…

数字信号的理解

1 数字信号处理简介 数字信号处理 digital signal processing&#xff08;DSP&#xff09;经常与实际的数字系统相混淆。这两个术语都暗示了不同的概念。数字信号处理在本质上比实际的数字系统稍微抽象一些。数字系统是涉及的硬件、二进制代码或数字域。这两个术语之间的普遍混…

cleanmymac和柠檬清理哪个好 cleanmymac有必要买吗

大家好&#xff0c;不定期分享正版软件激活安装、使用帮助&#xff0c;售后等知识。 在我们的日常使用中&#xff0c;电脑常常会出现卡顿、运行缓慢的情况。这时候&#xff0c;我们通常会想到清理电脑&#xff0c;以期望恢复电脑的正常运行状态。而在清理电脑时&#xff0c;有两…

FPC柔性线路板使用UV胶水的优势有哪些?

UV胶水在FPC柔性线路板的装配中具有明显的优势&#xff1a; 快速固化 UV胶水在紫外线照射后10秒左右迅速固化&#xff0c;因此它能够在短时间内完成连接。这非常有助于实际工业作业中提高生产效率&#xff0c;特别是在需要大批量生产的情况下。 精确控制固化时间 UV胶水的固…

在Next.js和React中搭建Cesium项目

在Next.js和React中搭建Cesium项目&#xff0c;需要确保Cesium能够与服务端渲染(SSR)兼容&#xff0c;因为Next.js默认是SSR的。Cesium是一个基于WebGL的地理信息可视化库&#xff0c;通常用于在网页中展示三维地球或地图。下面是一个基本的步骤&#xff0c;用于在Next.js项目中…

助力智能人群检测计数,基于DETR(DEtectionTRansformer)开发构建通用场景下人群检测计数识别系统

在一些人流量比较大的场合&#xff0c;或者是一些特殊时刻、时段、节假日等特殊时期下&#xff0c;密切关注当前系统所承载的人流量是十分必要的&#xff0c;对于超出系统负荷容量的情况做到及时预警对于管理团队来说是保障人员安全的重要手段&#xff0c;本文的主要目的是想要…