每日热议!实际业务中使用策略模式对代码进行重构
最近在负责公司一个语音的微服务模块优化,这个模块主要的业务是:1.天猫精灵、小度、若琪、小京鱼、小爱同学、思必驰这些第三方音响对我们的用户进行oauth2/JWT授权;2.这些第三方音响服务调用我们的设备发现接口对公司的设备信息在第三方平台进行一个存储;3.第三方平台对用户发出的语音进行解析,然后识别出需要控制的设备再调用我们的设备控制接口对公司的设备进行控制;
二.需要优化的点上述发现、控制接口分别写了五个API,并且在Controller层有着大量的业务校验,然后再在Controller层调用Service层的设备发现、控制方法;这些业务校验的逻辑一模一样;
字有点不好看,兄dei们献丑了,嘿嘿
(相关资料图)
三.优化(为方便演示这个举三个语音平台的例子)1.对不同平台的业务实现代码进行重构(图中的②)① 将之前的三个语音接口提取为同一个策略接口命名为:(VoiceStrategyService)public interface VoiceStrategyService { /** * @description: 语音控制API * @param: [jsonObject] * @return: com.alibaba.fastjson.JSONObject * @author: zhouhong * @date: 2023/5/18 9:34 */ JSONObject operateApi(@RequestBody JSONObject jsonObject);}② 其他几个实现类实现 (VoiceStrategyService) 这一个接口
其他几个语音实现类实现上面的那个策略接口,每个策略实现类对应一个业务场景,实现具体的方法逻辑。
@Service@Log4j2public class AliGenieServiceImpl implements VoiceStrategyService { @Override public JSONObject operateApi(JSONObject jsonObject) { log.info("天猫精灵-设备发现/控制成功!"); return null; }}
@Service@Log4j2public class DuerOSServiceImpl implements VoiceStrategyService { @Override public JSONObject operateApi(JSONObject jsonObject) { log.info("小度-设备发现/控制成功!"); return null; }}
@Service@Log4j2public class RokidServiceImpl implements VoiceStrategyService { @Override public JSONObject operateApi(JSONObject jsonObject) { log.info("若琪-设备发现/控制成功!"); return null; }}
@Service@Log4j2public class RokidServiceImpl implements VoiceStrategyService { @Override public JSONObject operateApi(JSONObject jsonObject) { log.info("若琪-设备发现/控制成功!"); return null; }}③接下来,定义一个上下文类(VoiceStrategyContext),该类持有一个策略对象,并提供一个方法用于设置策略对象
/** * @description: 语音策略上下文 * @author: zhouhong * @date: 2023/5/20 14:27 * @version: 1.0 */public class VoiceStrategyContext { @Resource private VoiceStrategyService voiceStrategyService; private void setVoiceStrategy(VoiceStrategyService voiceStrategyService) { this.voiceStrategyService = voiceStrategyService; } private JSONObject executeStrategy(JSONObject jsonObject) { if (voiceStrategyService != null) { return voiceStrategyService.operateApi(jsonObject); } return null; } /** * @description: 根据传过来的KEY值选择具体的策略 * @return: com.alibaba.fastjson.JSONObject * @author: zhouhong * @date: 2023/5/20 15:03 */ public JSONObject executeStrategyByKey(String key, JSONObject jsonObject) { switch (key) { case "aliGenie" : { this.setVoiceStrategy(new AliGenieServiceImpl()); return this.executeStrategy(jsonObject); } case "duerOS" : { this.setVoiceStrategy(new DuerOSServiceImpl()); return this.executeStrategy(jsonObject); } case "rokid" : { this.setVoiceStrategy(new RokidServiceImpl()); return this.executeStrategy(jsonObject); } default: { return null; } } }}
这个如果在下一层调用时知道自己需要调用哪个策略,那么executeStrategyByKey() 方法可以直接忽略,具体调用如下所示:
/** * @description: 测试类 * @author: zhouhong * @date: 2023/5/20 15:06 * @version: 1.0 */public class TextMain { public static void main(String[] args) { VoiceStrategyContext voiceStrategyContext = new VoiceStrategyContext(); JSONObject jsonObject = new JSONObject(); // 天猫精灵 voiceStrategyContext.setVoiceStrategy(new AliGenieServiceImpl()); voiceStrategyContext.executeStrategy(jsonObject); // 小度 voiceStrategyContext.setVoiceStrategy(new DuerOSServiceImpl()); voiceStrategyContext.executeStrategy(jsonObject); // 若琪 voiceStrategyContext.setVoiceStrategy(new RokidServiceImpl()); voiceStrategyContext.executeStrategy(jsonObject); }}
结果:
15:12:38.474 [main] INFO com.zhouhong.designpattern.strategy.service.impl.AliGenieServiceImpl - 天猫精灵-设备发现/控制成功!15:12:38.477 [main] INFO com.zhouhong.designpattern.strategy.service.impl.DuerOSServiceImpl - 小度-设备发现/控制成功!15:12:38.477 [main] INFO com.zhouhong.designpattern.strategy.service.impl.RokidServiceImpl - 若琪-设备发现/控制成功!
2.对开始那张图的 ① 进行代码提取这个比较简单,直接选中需要提取的代码块 Windows系统中 按住Ctrl 和 Alt 再加 M 键,就可以快速的将需要提取的代码从方法中抽离出来,然后新建一个Service层接口对其进行实现即可,主要示例代码如下:
/** * @description: 语音控制公共方法抽取 * @author: zhouhong * @date: 2023/5/17 10:58 * @version: 1.0 */public interface VoiceCommonApiService { /** * @description: 语音控制公共方法抽取 -- RequestBody格式 * @param: [jsonObject, platform] * @return: com.alibaba.fastjson.JSONObject * @author: zhouhong * @date: 2023/5/17 11:00 */ JSONObject voiceRequestBodyCommonApi(JSONObject jsonObject, String platform);}
/** * @description: 语音公共方法抽离 * @author: zhouhong * @date: 2023/5/17 11:00 * @version: 1.0 */@Service@Log4j2public class VoiceCommonApiServiceImpl implements VoiceCommonApiService { @Resource private VoiceStrategyContext voiceStrategyContext; @Override public JSONObject voiceRequestBodyCommonApi(JSONObject jsonObject, String platform) { log.info("大量逻辑校验代码......"); voiceStrategyContext.executeStrategyByKey(platform, jsonObject); log.info("其他业务代码......"); return null; }}
优化完工
四.设计模式总结1.简介策略模式是一种行为型设计模式,它允许在运行时选择算法的行为。该模式将不同的算法封装在各自独立的策略类中,使得它们可以互相替换,而不会影响到客户端代码。
2.主要参与角色环境类(Context):环境类持有一个策略对象,并在需要执行算法时调用策略对象的方法。它提供了一个接口供客户端代码设置策略对象。
抽象策略类(Strategy):定义了策略对象的接口或抽象类。它描述了算法的通用行为,可以包含算法的输入参数。
具体策略类(Concrete Strategy):实现了策略接口或继承了抽象策略类,并提供了具体的算法实现
3.工作流程客户端代码创建一个环境对象(Context)。
客户端根据需求选择一个具体策略类,并将其设置到环境对象中。
环境对象在需要执行算法的时候,调用所持有的策略对象的方法。
策略对象根据自身的算法实现进行处理,并返回结果给环境对象。
客户端通过环境对象获取算法的结果。
4.使用场景多种算法选择:当有多个算法可供选择,且需要在运行时动态选择其中一种算法时,可以使用策略模式。例如,在图像处理中,可以根据不同的要求选择不同的压缩算法。
避免条件语句:当代码中存在大量的条件语句用于根据不同条件执行不同的行为时,可以考虑使用策略模式来替代这些条件语句。策略模式将每种行为封装在单独的策略类中,使代码更加清晰、可维护。
动态配置行为:当需要动态地配置对象的行为时,可以使用策略模式。例如,在电商系统中,可以根据用户的会员级别,动态选择不同的折扣策略。
可扩展性:策略模式提供了一种可扩展的方式,允许添加新的策略类来满足新的需求,而无需修改现有代码。这种灵活性使得策略模式在需要频繁添加新的算法或行为的情况下非常有用。
单一职责原则:策略模式可以将不同的算法或行为分离到各自的策略类中,遵循了单一职责原则,使得每个类只关注自己的策略实现。
5.优缺点优点:
提供了一种清晰的方式来管理不同算法的实现,并将其与客户端代码解耦。策略类可以灵活地替换和扩展,不会对客户端代码造成影响。提高了代码的可维护性和可读性,减少了大量的条件语句。缺点:
增加了类的数量,每个具体策略类都需要单独实现一个类。五.示例代码地址https://github.com/Tom-shushu/work-study.git 代码中的design-pattern 项目
标签:
相关文章
天天微头条丨河南许昌2.9级地震 3级地震什么感觉(今日/头条)
一、河南许昌2 9级地震中国地震台网正式测定:05月20日09时03分在河南许昌市长葛市(北纬34 26度,东经113
美国商品期货交易委员会(CFTC):截至5月16日当周,投机者将CBOT美国2年期国债期货净空头持仓增加103690手-环球快讯
美国商品期货交易委员会(CFTC):截至5月16日当周,投机者将COT美国2年期国债期货净空头持仓增加103690手
Netflix 版《美猴王》动画电影定档 8 月 18 日,周星驰监制|天天热推荐
感谢指股网网友雨雪载途、华南吴彦祖、你好啊_兔子、指股网从官方获取到,该片由安东尼?斯塔奇(《盒子怪》
全球热议:博硕科技(300951):5月19日北向资金减持1.2万股
5月19日北向资金减持1 2万股博硕科技。近5个交易日中,获北向资金增持的有2天,累计净增持6100 0股。近20个
泡泡玛特(09992.HK):5月19日南向资金减持125.9万股
5月19日北向资金减持125 9万股泡泡玛特(09992 HK)。近5个交易日中,获南向资金减持的有2天,累计净减持12
铭汉股份拟向银行申请不超过1000万贷款 公司实际控制人王照及子公司为该事项提供连带责任保证|全球讯息
铭汉股份拟向银行申请不超过1000万贷款公司实际控制人王照及子公司为该事项提供连带责任保证,贷款,科学家,
《闪电侠》发布“双闪同行”预告片 冲破时空只为亲情永驻|世界快资讯
由华纳兄弟影片公司发行的DC超级英雄电影《闪电侠》(TheFlash)今日发布“双闪同行”预告片,时空扭转、双闪
当前视点!象州县气象台发布雷电黄色预警信号【III级/较重】【2023-05-19】
象州县气象台2023年5月19日16时31分发布雷电黄色预警信号:预计未来6小时内象州县部分乡镇可能发生雷电活动
功夫不负有心人的意思是什么_功夫不负有心人的意思_热头条
1、“功夫不负有心人”是一句很有名的俗语(谚语)。2、意思是只要勤奋、认真地对待所做的事。3、就一定能
吃“自助餐”,江边游泳嬉戏,亚洲象的生活也太让人羡慕了!_世界快看
亚洲象是亚洲现存最大的陆生动物,它们食量大,为了觅食,亚洲象会根据食物的季节变化而移动。5月17日,记
【西安白癜风专科医院】诱发老年白癜风的原因有哪些_每日焦点
【西安白癜风专科医院】诱发老年白癜风的原因有哪些?老年白癜风是指65岁或以上年龄段出现的白癜风。它
雷阵雨,局地大风+冰雹!北京发布雷电黄色预警
北京日报客户端|记者骆倩雯北京市气象台2023年5月19日14时30分发布雷电黄色预警信号:预计,当前至20时本市
青岛银行与山东省非公协会战略合作 服务辖区北交所上市公司等
青岛银行表示,未来将携手山东省非上市公众公司协会,为辖区北交所上市公司和新三板挂牌公司提供全方位、多
推特称微软违反开发者协议,使用数据没有付费
据报道,马斯克个人律师亚历克斯·斯皮罗代表Twitter致信微软CEO纳德拉,Twitter认为微软违反了Twitter开发