代码重构:过长的消息链(Message Chains)
【摘要】 什么是过长的消息链(Message Chains)定义:如果你看到用户向一个对象请求另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象……这就是消息链。在实际代码中你看到的可能是一长串取值函数或一长串临时变量。影响:客户端代码将与查找过程中的调用结构紧密耦合。一旦对象间的关系发生任何变化,客户端就不得不做出相应修改。改进目标:针对过长消息链,可以用这时候应该使用隐藏委托关系,把调...
什么是过长的消息链(Message Chains)
- 定义:如果你看到用户向一个对象请求另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象……这就是消息链。在实际代码中你看到的可能是一长串取值函数或一长串临时变量。
- 影响:客户端代码将与查找过程中的调用结构紧密耦合。一旦对象间的关系发生任何变化,客户端就不得不做出相应修改。
- 改进目标:针对过长消息链,可以用这时候应该使用隐藏委托关系,把调用链这种耦合关系放在中间人中。
- 方法:
1.观察清楚消息链的调用业务逻辑。
2.通过提炼函数把所有相同调用放在一个函数中
3.搬移函数到对应的中间人类中(新增或者使用以前的类)
4.替换这个函数到之前调用链。隐藏委托关系 - 注:有些人把任何函数链都视为坏东西,我们不这样想。我们的冷静镇定是出了名的,起码在这件事上是这样的。
案例1
代码背景
- 一个客户端期望能访问一个人的部门地址的门牌号和具体地址。
- 普通实现如果采用消息链调用的方式,调用方式为:person.getDepartment().getAddress().getStreet().getStreetName()
症状/问题
- InformationClient会知道整个Person依赖关系和组织实现,形成耦合关系。
- 消息链太长导致代码不易重构,不易修改。如果Person内部依赖关系或数据结构进行调整、重构,那么外部调用链同时被修改。
重构方法/目标
- InformationClient直接访问Person就能得出Street对象(这里是部门对象)
- 人、部门、地址、街道整个依赖关系对client透明。
- 后面如果发生变化和重构,外部无感知。
改进方式
- 改进前:Client感知到了整个内部逻辑,形成依赖
- 改进后:隐藏了内部数据结构依赖关系,使用Person作为“中间人”,为Client屏蔽委托关系
引申知识
- 过长的消息链到底是在说什么?到底有什么问题,为什么需要修改?深模块VS 浅模块
深模块:
- 最好的模块提供了强大的功能,又有着简单的接口。术语“深”可以用于描述这种模块。
- 可以从成本与收益的角度思考模块深度。模块提供的收益是它的功能。
- 模块的成本(从系统复杂度的角度考虑)是它的接口。接口代表了模块施加给系统其余部分的复杂度。接口越小而简单,它引入的复杂度就越少。
- 好的模块就是那些成本低收益高的模块。
浅模块:
- 就是模块内部暴露给外部调用或者使用,内部没有隐藏太多的逻辑,外部都能感知到内部的具体逻辑或者结构组织,或调用关系。
- 上述修改前的代码就是一个典型的浅模块的暴露和外部调用,外部是可以感知到内部实现的,是一种典型的不好的代码设计。
最后:Classitis
- 当今,深模块的价值并没有被广为接受。一般常识是类需要小,而不是深。学生们被告知:类设计中最重要的事情是把大类拆分成更小的类。
- 相似的建议还包括:“要把方法行数大于N的方法分成多个方法”,有时候N甚至只有10这么小。这会导致大量的浅模块,增加系统的总复杂度。
- 极端的“类应该小”的做法是一种综合症的表现,这种症状可以被称为Classitis。
- 它源于一种错误思维:“类是好的,所以越多类越好”。
- 这种思想最终会导致系统层面积累了巨大的复杂度,程序风格也会变得啰嗦。
总结
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)