首页 > 其他分享 >实际业务中使用策略模式对代码进行重构

实际业务中使用策略模式对代码进行重构

时间:2023-05-20 15:33:34浏览次数:46  
标签:重构 return 策略 jsonObject 代码 模式 JSONObject public

一.业务描述

最近在负责公司一个语音的微服务模块优化,这个模块主要的业务是: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
@Log4j2
public class AliGenieServiceImpl implements VoiceStrategyService {
    @Override
    public JSONObject operateApi(JSONObject jsonObject) {
        log.info("天猫精灵-设备发现/控制成功!");
        return null;
    }
}
@Service
@Log4j2
public class DuerOSServiceImpl implements VoiceStrategyService {
    @Override
    public JSONObject operateApi(JSONObject jsonObject) {
        log.info("小度-设备发现/控制成功!");
        return null;
    }
}
@Service
@Log4j2
public class RokidServiceImpl implements VoiceStrategyService {
    @Override
    public JSONObject operateApi(JSONObject jsonObject) {
        log.info("若琪-设备发现/控制成功!");
        return null;
    }
}
@Service
@Log4j2
public 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
@Log4j2
public 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.主要参与角色

  1. 环境类(Context):环境类持有一个策略对象,并在需要执行算法时调用策略对象的方法。它提供了一个接口供客户端代码设置策略对象。

  2. 抽象策略类(Strategy):定义了策略对象的接口或抽象类。它描述了算法的通用行为,可以包含算法的输入参数。

  3. 具体策略类(Concrete Strategy):实现了策略接口或继承了抽象策略类,并提供了具体的算法实现

3.工作流程

  1. 客户端代码创建一个环境对象(Context)。

  2. 客户端根据需求选择一个具体策略类,并将其设置到环境对象中。

  3. 环境对象在需要执行算法的时候,调用所持有的策略对象的方法。

  4. 策略对象根据自身的算法实现进行处理,并返回结果给环境对象。

  5. 客户端通过环境对象获取算法的结果。

4.使用场景

  1. 多种算法选择:当有多个算法可供选择,且需要在运行时动态选择其中一种算法时,可以使用策略模式。例如,在图像处理中,可以根据不同的要求选择不同的压缩算法。

  2. 避免条件语句:当代码中存在大量的条件语句用于根据不同条件执行不同的行为时,可以考虑使用策略模式来替代这些条件语句。策略模式将每种行为封装在单独的策略类中,使代码更加清晰、可维护。

  3. 动态配置行为:当需要动态地配置对象的行为时,可以使用策略模式。例如,在电商系统中,可以根据用户的会员级别,动态选择不同的折扣策略。

  4. 可扩展性:策略模式提供了一种可扩展的方式,允许添加新的策略类来满足新的需求,而无需修改现有代码。这种灵活性使得策略模式在需要频繁添加新的算法或行为的情况下非常有用。

  5. 单一职责原则:策略模式可以将不同的算法或行为分离到各自的策略类中,遵循了单一职责原则,使得每个类只关注自己的策略实现。

5.优缺点

优点:

  • 提供了一种清晰的方式来管理不同算法的实现,并将其与客户端代码解耦。
  • 策略类可以灵活地替换和扩展,不会对客户端代码造成影响。
  • 提高了代码的可维护性和可读性,减少了大量的条件语句。

缺点:

  • 增加了类的数量,每个具体策略类都需要单独实现一个类。

五.示例代码地址

https://github.com/Tom-shushu/work-study.git    代码中的 design-pattern 项目

标签:重构,return,策略,jsonObject,代码,模式,JSONObject,public
From: https://www.cnblogs.com/Tom-shushu/p/17417295.html

相关文章

  • 代码随想录算法训练营第十一天|20. 有效的括号、1047. 删除字符串中的所有相邻重复项
    【参考链接】20.有效的括号【注意】1.括号匹配是使用栈解决的经典问题。2.这个命令最后进入a目录,系统是如何知道进入了a目录呢,这就是栈的应用(其实可以出一道相应的面试题了)。3.有三种不匹配的情况,第一种情况,字符串里左方向的括号多余了;第二种情况,括号没有多余,但是括号的......
  • 学习一个跨境电商独立站的网站代码
    由于跨境电商独立站的网站代码涉及到具体的业务需求和技术实现,因此需要根据具体情况进行编写。以下是一个简单的示例网站代码,供您参考:首先,在您的本地电脑上创建一个新的文本文件,并将以下代码复制到该文件中:php复制代码<!DOCTYPEhtml><htmllang="zh"><head>......
  • 代码随想录Day6
    链表的复习章节  哈希的概念和应用:https://programmercarl.com/哈希表理论基础.html#哈希函数当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。数组set(集合)map(映射)这里数组就没啥可说的了,我们来看一下set。 Leetcode242时间复杂度O(N......
  • 适配器模式改造Servlet
    1. 我们编写一个Servlet类直接实现Servlet接口有什么缺点?  11  - 我们只需要service方法,其他方法大部分情况下是不需要使用的。代码很丑陋。2. 适配器设计模式Adapter   11  - 手机直接插到220V的电压上,手机直接就报废了。怎么办?可以找一个充电器。这个充电器就是一个......
  • 聊聊Seata分布式解决方案AT模式的实现原理
    什么是Seata分布式事务解决方案Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案。AT模式AT模式目前来看是Seata框架独有的一种模式,其它的分布式框架上并没有此种模式......
  • RabbitMQ工作模式-Routing模式
    路由模式:1、每个消费者监听自己的队列,并且设置routingkey。2、生产者将消息发给交换机,由交换机根据routingkey来转发消息到指定的队列。 Routing模式是可以完成订阅模式的工作的,下面的代码在RoutingKey为“inform”的消息中有所体现示例代码:生产者:publicclassP......
  • 代码一直在rebasing master状态,怎么重制到最新代码(不管之前的所有更改)
    根据你的gitstatus输出,你正在进行一个rebase操作,而且还有未完成的操作。如果你只想要让分支在最新的代码上,可以放弃当前的rebase操作,并从远程仓库拉取最新的代码,可以按照以下步骤进行操作:执行gitrebase--abort命令来放弃当前的rebase操作。执行gitfetchorigin......
  • 我写了本开源书:《3D编程模式》
    大家好,我写了本开源书,罗列了我从自己的实战项目中提炼出来的关于3D编程(主要包括“3D引擎/游戏引擎”、“编辑器”开发)的各种编程模式本书的在线阅读地址在这里:在线阅读本书的源码在Github中,欢迎star,感恩您:Github地址本书的写作花了我300多个小时,将近3个月的全职写作,凝结了我一......
  • 视频】复杂网络分析CNA简介与R语言对婚礼数据聚类社区检测和可视化|数据分享|附代码数
    最近我们被客户要求撰写关于复杂网络分析的研究报告,包括一些图形和统计输出。复杂网络分析研究如何识别、描述、可视化和分析复杂网络。为了用R来处理网络数据,我们使用婚礼数据集CNA研究和应用爆炸式增长的突出原因是两个因素-一个是廉价而强大的计算机的可用性,使在数学、物理......
  • 如何在代码开发中便捷使用 ChatGPT 协助开发
    在五一节前后,抽空测试了下网上推荐的开发环境和开发插件,在这里推荐给前后端代码开发的同胞们。方法一:IDEA安装插件bito习惯使用IDEA开发代码的同胞,可以尝试直接在IDEA中安装插件bito,注意操作过程中需要注册账号并登录。如下。安装成功后在右侧栏可以看到快捷导航图标,如下。......