提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 背景
  • 痛点
  • 一、如何根据不同条件获取不同的数据库Mapper?
  • 二、如何根据不同条件创建相应的数据库实体对象?
  • 总结

背景

本人在项目中遇到了一种情况是,两组功能模块的service层业务逻辑几乎完全相同。只是controller层传入的实体不同,以及Dao层采用的mapper不同(本项目持久层框架采用的是Mybatis-plus)。因此我希望可以使用一套service层代码,通过参数控制获取不同的mapper来实现不同条件的数据库操作,前提是不使用 if -else 这种不符合开闭原则的代码。

痛点

针对这种情况,如果不采用设计模式,就会导致需要编写两套几乎完全相同的代码,工作量非常大,而且扩展性差,如果后续业务需要再增加一组模块,则还需要再编写一套代码,费时费力,代码冗余。因此,本人选择了采用了工程模式+策略模式以及结合了java反射机制,解决了上诉的痛点。下面我就结果我开发时候的设计思路。


提示:以下是结合我个人开发的思路顺序来记录的

一、如何根据不同条件获取不同的数据库Mapper?

上面提到,我们的service层逻辑几乎相同,因此我希望的是可以通过传参数的方式获取不同条件下的mapper来进行数据库操作。前提是不使用if-else这种很low,而且扩展性很差,不符合开闭原则的方式。因此,我首先想到的就是策略模式,我把不同的mapper想象成不同的策略。标准的策略模式类图如下:

如果单独使用策略模式的话,实现的类图如下所示,该图是我真正实现的类图,其中IService 为mybatis-plus封装的接口,具体对数据库的操作需要继承IService,会mybatis-plus的同学自然明白,XXXServiceImpl为自己创建的对数据进行操作的实现类,即所谓的mapper,也是我们要获得的策略。

但是,单独使用策略模式的时候我发现个问题,就是获取策略的上下文类congtext,需要依赖ISerivce,即策略的父类。这个时候,我想到,是否可以结合工厂模式,通过工厂模式来获取相应的策略类,而不是通过这种上下文依赖的方式来获取策略,这样体现了工厂模式的优势,即用上下文工厂来替代传统策略模式获取策略的方式。因此,按照我的想法我做了类图的设计,对上述类图进行了改进,工厂模式+策略模式结合的类图如下:

经过上图的设计,我可以实现传入变量获取相应的数据库操作实现类,代码如下:

IService contractStrategy = ContractStrategyContextFactory.createStrategy(contractType);

工厂类中的方法如下:

 //因为涉密,仅截取部分代码片段private static Map<String, ServiceImpl> hashmap = new HashMap<>();@PostConstructprivate void init(){hashmap.put(ContractMapperEnum.SERVICE_CONTRACT.getType(),serviceContractInfoService);hashmap.put(ContractMapperEnum.SPARE_PARTS_CONTRACT.getType(),sparePartsContractInfoService);}public static IService createStrategy(String type){return hashmap.get(type);}

因此,我们需求的第一步就得以实现了,通过不同接口传入的参数不同,调用不同的数据库操作类,并且没有使用任何的if else判断,降低了耦合性,并且满足了开闭原则。但是,获取到的IServie的范型是T,那么问题来了,如何根据接口参数的不同,生成相应的数据库实体对象呢,因为,BeanUtils.copyProperties来复制相应的数据库实体对象时,要先创建好实体类对象,如果问题不解决,那么我们还需要用if else来进行判断,来创建对应数据库的实体类对象。解决方式看第二部分。

二、如何根据不同条件创建相应的数据库实体对象?

首先,我知道java创建对象的方式有三种,分别是 new 、拷贝以及反射。所以,这里我第一时间想到了就是反射的方式,即 Class.forName()获取类,再用newInstance()方法创建对象,但是,这个方法返回的类中需要预先知道类的范型,不然创建的对象全部都是object,无法对数据库实体类对象进行字段的set方法。这时,我想到了继承的方式,将数据库实体类抽象出统一的父类BaseEntity,然后创建子类并用父类来作为反射的接收类,然后再进行实例化,BeanUtils.copyProperties就可以将属性copy到父类对象中,具体实现如下面的代码所示。最后将数据库实体类的父类对象,传入我们通过策略模式获取的数据库操作类,完成最后的数据库操作。此时流程全部结束,实现了我们的最终目的。

//获取数据库实体类,并用父类接收
Class<ContractTempBaseEntity> clazz = (Class<ContractTempBaseEntity>)Class.forName(className);
//实例化
ContractTempBaseEntity contractTempBaseEntity = clazz.newInstance();
//将接口参数copy到数据库实体类对象
BeanUtils.copyProperties(baseContractTempInfoDTO,contractTempBaseEntity);
//将对象传入到通过策略模式获取的数据库操作类,完成最后的数据库操作
contractStrategy.saveOrUpdate(contractTempBaseEntity);

以上涉及到的枚举类如下:

//枚举类例子
SPARE_PARTS_CONTRACT("SparePartsContractInfo", "数据库实体类的类路径,作为class.forName的参数"),
SPARE_PARTS_CONTRACT_TEMP("SparePartsContractTempInfo","数据库实体类的类路径,作为class.forName的参数"),

总结

通过以上方式,基本上完成了需求的痛点,而且可以满足日后的扩展,最终从controller 到service再到Dao层的时序图如下:

工厂模式+策略模式+反射机制解决系统功能模块相似的问题相关推荐

  1. java-抽象工厂模式+工厂方法模式+策略模式简单应用实战(登录场景)

    前言 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计模式的目的:为了代码可重用性.让代码更容易被他人理解.保证代码可靠性. 设计模式 ...

  2. 工厂模式+策略模式组合实现电商促销活动

    项目中大多数设计模式都是组合使用的,对于单个设计模式小伙伴们可以去菜鸟教程学习一下,下面使用 Java 实现的工厂模式+策略模式组合实现电商促销 首先,根据策略的不同,一些需要优惠计算,一些需要普通计 ...

  3. springboot 使用工厂模式+策略模式替代多重if 案例

    项目背景: 由于做的是物联网项目,现在需要实现的是网关入网+子设备注册:网关有3个逻辑,分别为首次入网.解绑后同一个人入网(恢复).解绑后换人入网(换人).子设备注册: 原先写法是: if(type ...

  4. 混合模式(工厂方法模式+策略模式+门面模式)

    混合模式(工厂方法模式+策略模式+门面模式) 使用这三种模式设计一个简单的计算器程序:计算器是用于计算数值之间进行数学计算后所获得的值.它包含基本的"加减"功能.以上对以上需求进行 ...

  5. 进阶学习之旅-设计模式之(委派模式策略模式)

    文章目录 1.课程学习目标 2.内容定位 3.委派模式详解 3.1委派模式的定义 3.2 demo案例 3.2.1模拟Boss指派任务给Leader 由员工完成任务执行 3.2.2 模拟spring ...

  6. 23种模式——策略模式

    目录 策略模式 策略模式的收银软件 策略模式的特点 使用场景 优缺点 策略模式和工厂模式的结合 策略(Strategy)模式 本质:分离算法,选择实现. 策略模式:针对一组算法,将每一个算法封装到具有 ...

  7. 模板模式+策略模式优化

    前言 写在最前面,最近在项目中发现一部分代码,可以用模板模式+策略模式来进行优化. 背景 业务中,系统中对订单状态的处理,需要发送对用户短信发送或者微信推送等操作. 发送短信和微信推送钱,需要处理逻辑 ...

  8. 设计模式 — 行为型模式 — 策略模式

    目录 文章目录 目录 策略模式 应用场景 代码示例 策略模式 策略模式中,首先定义了一系列不同的算法,并把它们一一封装起来,然后在策略类中,使这些算法可以相互替换.这意味着,让一个类的行为(算法)可以 ...

  9. 3.js模式-策略模式

    1. 策略模式 策略模式定义一系列的算法,把它们封装起来,并且可以互相替换. var strategies = { isNonEmpty: function(value,errMsg){ if(val ...

最新文章

  1. 装上后这 14 个插件后,PyCharm 真的是无敌的存在
  2. 书评与访谈:the Scrumban [R]Evolution
  3. 阿里云发布云电脑“无影”,「传统桌面云」市场将被颠覆?
  4. 将输入的中文按要求翻译成拼音
  5. 常用SQL语句优化技巧总结
  6. C++类构造析构调用顺序训练(复习专用)
  7. HTML label标签学习笔记
  8. IOS-awakeFromNib和viewDidLoad
  9. mysql指令按顺序排列_mysql基本语法大全
  10. 架​设​W​e​b​服​务​器
  11. 城市APP集成Firebase/Admob/增强现实带PHP管理后台
  12. python基础一 day17 二分查找算法
  13. flex4与java_Flex4与java传递对象
  14. 计算机C语言课程内容,计算机C语言课程主要内容简介.ppt
  15. 阿里云服务器搭建halo博客从0到1
  16. 怎么通过Win pe下面注册表编辑器载入原来系统注册表更改信息
  17. 贝叶斯算法-情感分类
  18. 若依框架(RuoYi-Vue):权限功能模块设计分析
  19. 谨慎处理单片机中断,中断等价于比主程序优先级更高的线程
  20. 冰河浅析 - 揭开***的神秘面纱(下)

热门文章

  1. java ffmpeg 合并视频_java使用ffmpeg进行多个视频合并
  2. nth-child选择器;奇数偶数作为关键字
  3. Linux之——使用wget命令爬取整站
  4. 【MySQL】with rollup的用法
  5. 淘宝开网店提高店铺转化率的28原则
  6. 店铺有展现没有点击怎么办
  7. MacBook pro 2018款死机或出现故障的重启问题
  8. VoIP Push 在海外音视频业务中的应用
  9. Linux下编译FFMPEG 使用ndk r20
  10. 问题 A: 宾馆房间开门问题