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

简介: 【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设计模式七大原则-接口隔离原则
90 0
|
设计模式 Java 数据库
Java设计模式七大原则-依赖倒转原则
Java设计模式七大原则-依赖倒转原则
88 0
七大设计原则之迪米特法则应用
七大设计原则之迪米特法则应用
83 0
|
算法 Java 数据处理
依赖倒转原则是什么?
依赖倒转原则是什么?
|
6月前
|
设计模式 Java
Java设计模式七大原则之依赖倒置原则
Java设计模式七大原则之依赖倒置原则
64 0
|
6月前
|
设计模式 Java 开发者
Java设计模式七大原则之里氏替换原则
Java设计模式七大原则之里氏替换原则
53 0
|
6月前
|
设计模式 安全 Java
Java设计模式七大原则之开闭原则
Java设计模式七大原则之开闭原则
77 0
|
设计模式 Java
Java设计模式七大原则-迪米特法则
Java设计模式七大原则-迪米特法则
64 0
|
设计模式 Java
Java设计模式七大原则-单一职责原则
Java设计模式七大原则-单一职责原则
82 0
|
设计模式
设计模式 - 六大设计原则之LoD(迪米特法则原则)
迪米特法(Law Of Demeter , LoD)则又叫最少知道原则(Least Knowledge Principle),最早是在1987年由美国Northeastern University的Ian Holland提出。 通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。
192 0
设计模式 - 六大设计原则之LoD(迪米特法则原则)