通过一个简单的应用案例来说说迪米特法则

简介: 【8月更文挑战第1天】

代码案例

先贴代码:

protected String convertResData(ExecuteContext executeContext) {
    if (Constant.SUCCESS.equals(executeContext.getResponseMessageVO().getResCode())) {
        return this.convertResData(executeContext.getResponseMessageVO().getResData());
    } else {
        if(BossKgConstant.ERROR_6216.equals(executeContext.getResponseMessageVO().getResCode())) {
            executeContext.getResponseMessageVO().setResCode(Constant.ERROR_6217);
        }
        if(BossKgConstant.ERROR_6221.equals(executeContext.getResponseMessageVO().getResCode())) {
            executeContext.getResponseMessageVO().setResCode(Constant.ERROR_6224);
        }
        if(BossKgConstant.ERROR_6222.equals(executeContext.getResponseMessageVO().getResCode())) {
            executeContext.getResponseMessageVO().setResCode(Constant.ERROR_6222);
        }
        if(BossKgConstant.ERROR_6223.equals(executeContext.getResponseMessageVO().getResCode())) {
            executeContext.getResponseMessageVO().setResCode(Constant.ERROR_6223);
        }
        return "";
    }
}

上面的 convertResData 方法,应该重构为:

protected String convertResData(ResponseMessageVO responseMessageVO) {
    if (Constant.SUCCESS.equals(responseMessageVO.getResCode())) {
        return this.convertResData(responseMessageVO.getResData());
    } else {
        if (BossKgConstant.ERROR_6216.equals(responseMessageVO.getResCode())) {
            responseMessageVO.setResCode(Constant.ERROR_6217);
        }
        if (BossKgConstant.ERROR_6221.equals(responseMessageVO.getResCode())) {
            responseMessageVO.setResCode(Constant.ERROR_6224);
        }
        if (BossKgConstant.ERROR_6222.equals(responseMessageVO.getResCode())) {
            responseMessageVO.setResCode(Constant.ERROR_6222);
        }
        if (BossKgConstant.ERROR_6223.equals(responseMessageVO.getResCode())) {
            responseMessageVO.setResCode(Constant.ERROR_6223);
        }
        return "";
    }
}


我们重构的是这个 convertResData 方法的入参。从代码实现逻辑可以看出来, 它只关注 ExecuteContext 类的 responseMessageVO 属性。因此,我们让这个方法只接收 ResponseMessageVO 对象即可,减少不必要的对象交互。


这段代码重构,涉及到一个很重要的设计原则——迪米特法则。


迪米特法则

迪米特法则(Law of Demeter, LoD),又称最少知识原则(Least Knowledge Principle,LKP),它指导我们在设计软件时,应当尽量减少对象之间的交互,一个对象应该对其他对象有尽可能少的了解。

具体来说,一个对象应该只调用属于以下范畴的方法:

  • ①本对象自己的方法
  • ②作为方法参数传入的对象的方法
  • ③该方法内部创建或实例化的对象的方法
  • ④对象持有的任何组件的方法

怎么形象地理解这4点?

talk is cheap, show me the code. 还是看代码来得直接↓

@Service
@Slf4j
public class PaymentQueryBizService {
 
    @Autowired
    private RedisDistributedLock distributedLock;
 
    @Autowired
    private BankOrderFlowService bankOrderFlowService;
 
    @Autowired
    private PayErrorCodeService payErrorCodeService;
 
 
    public OrderPayStatusEnum paymentQuery(BankOrderFlow bankOrderFlow) {
        AssertUtil.notNull(bankOrderFlow.getFlowNo());  //              ②作为方法参数传入的对象的方法
 
        String key = ...;
        if (!distributedLock.lock(key, TimeUnit.MINUTES.toMillis(5))) {     //      ④对象持有的任何组件的方法
            throw BizException.build("获取分布式锁失败");
        }
 
        Map<String, String[]> map=new HashMap<>();
        map.put(...);               // ③该方法内部创建或实例化的对象的方法
 
        try {
            ...
 
            BankPayService bankPayService = StrategyManager.byStrategy(BankPayService.class, productSubTypeEnum);
 
            //查询通道
            PaymentTransQueryDTO paymentTransQueryDTO = bankPayService.payQuery(bankOrderFlow, channelConfig);  //       ③该方法内部创建或实例化的对象的方法
            //匹配错误码 如果命中则将订单置为失败
            if (!OrderPayStatusEnum.isFinalState(paymentTransQueryDTO.getOrderStatus())) {
                matchErrorCode(bankOrderFlow, paymentTransQueryDTO);            //          ①本对象自己的方法
            }
            return bankOrderFlowService.updateTransQueryResult(bankOrderFlow, paymentTransQueryDTO);    //  ④对象持有的任何组件的方法
        } finally {
            distributedLock.releaseLock(key);       //      ④对象持有的任何组件的方法
        }
    }
 
    private void matchErrorCode(BankOrderFlow bankOrderFlow, PaymentTransQueryDTO paymentTransQueryDTO) {
        ...
            
        log.info("交易查询-验证错误码-请求入参:{}", checkErrorCode);      //  是 ① 还是 ② 还是 ③ 还是 ④ ?
        CheckResult check = payErrorCodeService.check(checkErrorCode);      //      ④对象持有的任何组件的方法
        if (check.yes()) {
            paymentTransQueryDTO.setOrderStatus(FAIL);  //              ②作为方法参数传入的对象的方法
        }
    }
    
}


应用场景

当软件系统中的类与类之间的关系过于复杂时,使用迪米特法则来降低耦合度。

在面向对象的设计中,尤其是在分层架构中,用于降低层与层之间的依赖。


目录
相关文章
String.format()函数的简单用法
1.String.format()函数的用法 2.常用转换符 3.常用标识
369 0
|
存储 测试技术 区块链
阿里云、百度云及移动云对象存储横向性能对比测试
在企业的数字化转型进程中,我们观察到越来越多的公司将其IT基础设施迁移到云端。随着企业业务的持续运营,无论是储存、处理、分享还是删除,都会产生大量的数据,这就要求有一个既可靠又高效的系统来管理和存储这些信息。对象存储产品在这个场景中扮演了至关重要的角色。它们以一种可扩展、安全、持久的方式,有效地满足了对大规模非结构化数据存储的需求。 尽管市场上云计算提供商众多,各自都有自己独特的对象存储产品,面对这样的丰富选择,如何寻找最符合企业需求的产品呢?这正是企业今天寻求解答的问题。 在本篇文章中,我们将深入进行一项横向对比测试,专门对阿里云OSS、百度云BOS和移动云EOS这三大云服务提供商的对象
3625 0
|
安全 Java Spring
【Java用法】Java 过滤html标签获取纯文本信息
【Java用法】Java 过滤html标签获取纯文本信息
448 0
|
并行计算 算法 计算机视觉
【MATLAB 】 CEEMDAN 信号分解+模糊熵(近似熵)算法
【MATLAB 】 CEEMDAN 信号分解+模糊熵(近似熵)算法
713 0
|
人工智能
IDEA完全免费AI辅助编程插件BITO-GPT4安装及中文国产化设置
IDEA完全免费AI辅助编程插件BITO-GPT4安装及中文国产化设置
1998 1
|
Unix Linux 数据安全/隐私保护
Linux服务器如何远程连接?服务器远程连接图文教程
服务器操作系统可以实现对计算机硬件与软件的直接控制和管理协调,任何计算机的运行离不开操作系统,服务器也一样,服务器操作系统主要分为四大流派:Windows Server、Netware、Unix和Linux。 今天驰网飞飞就给你们分享下Linux、Unix系统远程连接图文操作方法
281 4
Linux服务器如何远程连接?服务器远程连接图文教程
|
10月前
|
存储 资源调度 JavaScript
npm、cnpm 和 pnpm 是三种常用的 Node.js 包管理工具
npm、cnpm 和 pnpm 是三种常用的 Node.js 包管理工具。npm 是官方默认的包管理器,提供依赖管理、安装和更新等功能;cnpm 是由阿里巴巴开发的 npm 镜像,专为中国大陆用户优化,解决下载速度慢的问题;pnpm 通过硬链接技术提高安装速度并节省磁盘空间,特别适合磁盘资源紧张的环境。三者命令类似,但各有特色,开发者可根据需求选择合适的工具。
1092 5
|
SQL 监控 数据库
OceanBase社区版可以通过Zabbix监控
【10月更文挑战第5天】随着OceanBase社区版的广泛应用,企业纷纷采用这一高性能、高可用的分布式数据库系统。为了确保系统的稳定运行,使用成熟的Zabbix监控工具进行全面监控至关重要。本文通过具体示例介绍了如何配置Zabbix监控OceanBase,包括安装配置、创建监控模板和监控项、编写脚本、设置触发器及图形展示等步骤,帮助读者快速上手,及时发现并解决问题,确保业务始终处于最佳状态。
307 2
|
Docker 容器
docker:记录如何在x86架构上构造和使用arm架构的镜像
为了实现国产化适配,需将原x86平台上的Docker镜像转换为适用于ARM平台的镜像。本文介绍了如何配置Docker buildx环境,包括检查Docker版本、安装buildx插件、启用实验性功能及构建多平台镜像的具体步骤。通过这些操作,可以在x86平台上成功构建并运行ARM64镜像,实现跨平台的应用部署。
8889 2
VSCode 插件Code Runner 中文提示乱码
VSCode 插件Code Runner 中文提示乱码