背景介绍
最近在团队工作中花了不少心思主导建设了测试平台,前期的建设思路是能用就行,随着建设的深入,逐渐需要学习下代码架构设计方面的内容了。于是参加了公司组织的代码重构与模式的培训,通过培训,感觉收获颇丰,故有此文。
概要
重构与模式要解决的是软件的可维护性问题,主要围绕面向对象设计的5大原则开展。
分别是:
- 单一职责原则(SRP:The Single Responsibility Principle),也称:单职;
- 开放封闭原则(OCP:The Open Closed Principle);
- Liskov替换原则(LSP:The Liskov Substitution Principle);
- 接口隔离原则(ISP:The Interface Segregation Principle);
- 依赖倒置原则(DIP:The Dependency Inversion Principle);
这五个原则追求的效果是:高内聚低(松)耦合(High Cohesion Loose Couple)
五大原则
单一职责原则SRP
最简单也最难用对的原则
这里有个判断标准,就是代码变动的影响分析,例如下图中,代码变动的影响会蔓延。这种现象老师在上课中称之为【关我啥事儿】,也就是不相关的模块/类受到了影响。
如果外部GUILibrary的变动不影响不相关的内容,那么就是好的设计。
这里需要用到提取类的操作,分清楚类的职责。
提取类
目标:应该把代码组织的一次之做一件事儿
单一抽象层次原则
SLAP(Single Level of Abstraction Principle)
SRP总结
- 每个职责都是一个设计的变因
- 职责的耦合在需求发生变化时,回事设计遭到意想不到的破坏
- 内聚(Cohesion)是SRP原则的另外一个名字
- 仅当变化发生时,职责才具有实际的意义
- SRP是最简单,也最难正确运用的原则之一
- 软件设计要做的许多工作,就是发现职责并把它们相互分离
开放封闭原则OCP
这个原则的含义是:软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。
对扩展开放的含义是:模块的行为可扩展,可复用性好
对修改封闭的含义是:模块的源代码不可被修改,可维护性好。
例如:汽车计价的规则,最初如下
后来修改成了这样:
代码这样简单粗暴的修改就不好。虽然在业务简单的时候,这样修改确实高效,而且我们也长这么做,但是这样的代码不利于后期维护。
开放封闭原则强调:当业务变更时,通过增加代码来实现业务的变动,而不是修改代码。
用多态取代条件表达式
OCP :总结
- 改动是通过增加代码进行的,而不是修改现有的代码
- 通过创建抽象来隔离以后发生的同类变化
- 一旦写出了可以工作的代码,就要保证这段代码一直可以工作
- OCP 背后的机制:封装和抽象
- 没有100%的封闭,仅仅对频繁变化的部分做出抽象
Liskov替换原则 LSP
OCP 背后的主要机制: 抽象&多态
支持抽象&多态的关键机制: 继承
什么才是好的继承关系?
所有引用基类的地方必须能透明地使用其子类的对象
继承必须确保超类所拥有的性质(行为)在子类中仍然成立
应对方形不是矩形的方法:提升为兄弟类。将不符合 LSP 的子类提升为父类的兄弟类。
LSP总结
- LSP 是使 OCP 成为可能的主要原则之一
- 对于 LSP 的违反也潜在的违反了 OCP
- 所有引用基类的地方必须能透明地使用其子类的对象
- LSP 关注的是怎样良好的使用继承
- OOD 的 IS-A 关系是就行为而言
- 模型的有效性只能通过它的客户程序来检验
接口隔离原则 ISP
不要强迫用户去依赖那些他们不使用的接口。
如何分离接口
多继承
委托
ISP - 总结
- 接口必须是高内聚的
- 接口的划分是由使用它的客户程序决定的
- 接口包含太多行为会导致客户程序之间产生不正常的依赖关系
依赖倒置原则 DIP
高层模块不应该依赖于低层模块,它们都应该依赖于抽象。
抽象不应该依赖于细节,细节应该依赖于抽象。
依赖倒置的关键 -- 分层
所有结构良好的面向对象架构拥有清晰的分层,每个分层通过良好定义的接口提供条理分明的一系列服务。
DIP - 总结
- 依赖倒置原则体现了 OCP 和 LSP 的结构上的含义
- 高层模块包含了应用程序中重要的策略选择和业务模型
- 高层模块依赖底层模块,那么高层模块的重用会变得十分困难
- DIP的简单规则:依赖于抽象
- DIP可以应用于任何存在一个类向另一个类发送消息的地方
- 通过DIP我们可以创建更灵活 更持久、更容易改变的结构
对已知代码重构的套路
- 另起炉灶
- 搬移函数
- 子类化
- 多态调用
写在最后
这部分总结是将五大原则的使用思路进行了总结,里面有不少例子,尽管老师的培训讲解的很细致,但是自己并未能很充分的理解某些原则,因此在其中将自己能理解的内容,适当展开,不少内容在实际工作中并未认真思考和实践,对于不太理解的内容搬了过来,后续再消化。因此这次培训也算是打开了我进行代码重构、代码架构设计的一扇窗,希望之后能继续深入学习、实践!