代码案例
先贴代码:
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. 还是看代码来得直接↓
public class PaymentQueryBizService { private RedisDistributedLock distributedLock; private BankOrderFlowService bankOrderFlowService; 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); // ②作为方法参数传入的对象的方法 } } }
应用场景
当软件系统中的类与类之间的关系过于复杂时,使用迪米特法则来降低耦合度。
在面向对象的设计中,尤其是在分层架构中,用于降低层与层之间的依赖。