图论思想与UML应用 (上 )
图论是对现实世界中实际问题的高度抽象。
有向图可以对具有特定依赖关系的实体群落 ,进 行有效的抽象刻画 ,使人们能够忽略无关紧要的众多细节 ,而牢牢把握住本质性的依赖关系。
依赖关系在软件开发中的重要性 ,不管怎么强调都不过分。
响应变化的能力往往决定一 个项目的成败 ,
而依赖关系的处理 (其实不仅包括类与类等工件之间的依赖 ,还包括人之间 的依赖和活动之间的依赖 ,
本文不详细讨论)正是其中的关键。
著名的开放封闭原则 (Open-Closed Principle,OCP )规定 :
“软件实体应该是可以扩展 的 ,但是不可修改”。
本原则紧紧围绕变化展开 ,变化来临时 ,如果不必改动软件实体的源代 码 ,就能扩充它的行为 ,那么这个软件实体的设计就是满足开放封闭原则的。
如果我们预测 到某种变化 ,或者某种变化发生了 ,我们应当创建抽象来隔离以后发生的同类变化。
在Java中 ,这种抽象指抽象基类或接口 ;
在C++中 ,这种抽象是指抽象基类或纯抽象基类。
比如 ,在开发一个需求跟踪工具的时候 ,起初可能仅需要支持保存为专有格式的“项目”文 件 ,但后来又需要支持导出为HTML格式的网页。让我按照敏捷软件开发过程 ,来讲述这个 故事。
最开始的设计如下图所示 ,CReqMatrixDoc调用CProjectSaver来保存自己。按照开放封闭原则 (Open-Closed Principle ) ,这并不是一个好的设计。
但此时 ,所有需求就是支持“保 存为专有格式的项目文件” ,而且我们并没有预见到将来还需要以更多的形式保存 ,所以这个 设计“不多不少”刚刚好。
在这里插入图片描述
后来需求发生了变化 ,这个工具需要支持“导出为HTML格式的网页”的特性。是的 ,这个 需求不管是客户新提出来的 ,还是设计人员在上一个迭代有意忽略了 ,总之在这个迭代周期 需求发生了变化。于是 ,设计人员意识到 ,需求跟踪工具可能需要支持多种保存策略。
看来 ,代码出现了臭味 (Smell ) ,需要重构 (Refactoring )。
让我们谨遵Martin Fowler“两顶帽子”的教诲——
不要将重构和添加新功能同时进行——这一步我们仅进行重构。
我们要做的就是采用依赖倒置原则 (Dependency- Inversion Principle)惯用的“用两个抽象依 赖代替一个具体依赖”策略 ,重构之后的设计如下图所示。
我们引入了一个接口CDocSaver , 然后让CProjectSaver实现这个接口。
哈 ,新的设计满足开放封闭原则 ,究其原因 ,最关键的一点就是CProjectSaver对 CDocSaver接口的单向依赖。新设计非常易于扩充 ,我们只需新写一个CHtmlSaver来实现接 口CDocSaver ,就离支持“导出为HTML格式的网页”不远了 ,如下图所示。咦 ,原来是GOF 的Strategy模式。