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

简介: 【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);  //              ②作为方法参数传入的对象的方法
        }
    }
    
}


应用场景

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

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


目录
相关文章
|
设计模式 Java 测试技术
Java设计模式七大原则-接口隔离原则
Java设计模式七大原则-接口隔离原则
95 0
|
设计模式 Java 数据库
Java设计模式七大原则-依赖倒转原则
Java设计模式七大原则-依赖倒转原则
94 0
七大设计原则之迪米特法则应用
七大设计原则之迪米特法则应用
86 0
|
6月前
|
存储 测试技术
了解面向对象设计和方法
【6月更文挑战第26天】本文介绍面向对象编程(OOP)强调通过对象来模拟现实世界,以数据和行为的结合体形式存在。核心概念是封装、继承和多态,关系包括依赖、实现、关联、聚合和组合。组合是强于聚合的关联,当部分与整体有相同生命周期时适用。OOP允许创建复杂系统模型,如汽车的组件,提供不同层次的抽象。
78 1
了解面向对象设计和方法
|
7月前
|
设计模式 Java
Java设计模式七大原则之依赖倒置原则
Java设计模式七大原则之依赖倒置原则
73 0
|
7月前
|
设计模式 Java 开发者
Java设计模式七大原则之里氏替换原则
Java设计模式七大原则之里氏替换原则
61 0
|
7月前
|
设计模式 安全 Java
Java设计模式七大原则之开闭原则
Java设计模式七大原则之开闭原则
83 0
|
设计模式 Java
Java设计模式七大原则-迪米特法则
Java设计模式七大原则-迪米特法则
68 0
|
设计模式 消息中间件 Java
【Java设计模式 面向对象设计思想】三 再谈抽象类和接口
【Java设计模式 面向对象设计思想】三 再谈抽象类和接口
168 0
|
设计模式 XML JSON
【Java设计模式 经典设计原则】七 LOD迪米特法则
【Java设计模式 经典设计原则】七 LOD迪米特法则
114 0