前言
本系列内容为 Robert C. Martin 敏捷开发一书的读书笔记,前两篇介绍了敏捷开发的一些基本原则和方法,这一篇开始介绍 敏捷设计。
一、 什么是敏捷设计
1. 设计的臭味--腐化软件的气味
① 僵化性: 很难对系统进行改动,因为每个改动都会迫使许多对系统其他部分的其他改动。
② 脆弱性: 对系统的改动会导致系统中和改动的地方在概念上无关的许多地方出现问题。
③ 牢固性: 很难解开系统的纠结,使之成为一些可在其他系统中重用的组件。
④ 粘滞性: 做正确的事情比做错误的事情要困难。
⑤ 不必要的复杂性: 设计中包含有不具备任何直接好处的基础结构。
⑥ 不必要的重复: 设计中包含有本可以用单一的抽象进行统一的重复结构。
⑦ 晦涩性: 很难阅读、理解。没有很好的表现出意图。
敏捷在这方面的优势是 团队几乎不进行预先设计,而是愿意保持系统设计尽可能的干净、简单,并使用许多单元测试和验收测试作为支援。利用这种灵活性,持续的改进设计。
2. 如何避免
敏捷开发人员有三个准则:
① 他们遵循敏捷实践去发现问题;
② 他们应用设计原则去诊断问题;并且
③ 他们应用适当的设计模式去解决问题。
设计必须要保持干净、简单,源代码同样要时刻保持干净。作为软件开发人员,不能忍受代码腐化。
3. 结论
敏捷设计是一个过程,是一个持续的应用原则、模式以及实践来改进软件的结构和可读性的过程。
二、 单一职责原则(SRP)
就一个类而言,应该仅有一个引起它变化的原因。
1. 什么是职责
在SRP中,我们把职责定义为“变化的原因”。如果你能想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。
interface Modem { public void dial(String pno); public void hangup(); public void send(char c); public void recv(); }
* 根据需求权衡Modem中的四个方法,是否需要分离。连接和发送接收,一般认为是两个职责。
2. 于持久化的耦合
业务规则和持久化这两个职责在大多数情况下绝不应该混合在一起。业务规则往往会频繁的变化,而持久化的方式往往比较稳定,即使变化也是跟业务有不同的原因。
对于现有项目中的于持久化的耦合,应该考虑使用FACADE和PROXY模式对设计进行重构,分离这个职责。
3. 结论
SRP是所有原则中最简单的之一,也是最难正确运用的之一。
三、 开放-封闭原则(OCP)
软件实体(类、模块、函数等)应该是可以扩展,但是不可修改的。
1. 解释
遵循开发-封闭原则涉及出的模块具有两个主要的特征: 对扩展开放,对更改封闭。
2. 方法--使用抽象
模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,所以它对于更改可以是关闭的。同时,通过从这个抽象体派生,可以扩展此模块的行为。
3. 实际应用
通常,我们更愿意一直等到确实需要那些抽象时再把它放置进去。
① 只受一次愚弄:变化发生时,我们就创建抽象来隔离以后发生的同类变化。
② 刺激变化:通过 首先编写测试、很短的迭代周期、加入基础结构前就开发特性、尽早的经常性的发布软件 等方式来刺激变化的发生。
4. 使用抽象获得显示封闭
通过一种“顺序抽象体”中的抽象接口,可以表示任何可能的排序策略。从而让DrawAllShapes对于绘制顺序的变化是封闭的。
class Shape { public: virtual void Draw() const = 0; virtual bool Precedes(const Shape&) const = 0; bool operator<(const Shape& s) {return Precedes(s); } };
5. 使用“数据驱动”的方法获取封闭性
const char* Shape::typeOrderTable[] = { typeid(Circle).name(), typeid(Square).name(), 0 };
6. 结论
开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象。拒绝不成熟的抽象和抽象本身一样重要。
四、 Liskov 替换原则(LSP)
未完待续。。。