最近又翻起阎宏博士的《Java与模式》这本书,此书语言浅显易懂,且内容充实,值得反复阅读思考,就像好的电影都会让你想有时间再翻出来再看看,此书也是一样。
翻阅之中,觉得还是把内容摘抄下来,一是避免捧着这本大块头的痛苦,二是便于自己整理思路。
以下内容大部分摘自此书的第二部分。
什么情况下一个软件系统会变得“腐烂”:
1.僵硬:增加新功能要影响很多地方。
2.脆弱:一个地方的修改,会导致其他地方的发生变化或者故障。
3.复用率低:代码、函数等难以被程序员复用在软件的其他地方.
导致程序员重复造轮子,甚至cp&paste来使用已有代码。
4.粘度过高:当一个改动,可以按照原有设计框架进行,也可以另辟蹊径快速解决。
当第二种情况出现,则表示原系统设计粘度过高!
设计的目标:
1.Extensibility可扩展性:与“僵硬”相反,一个功能可以很容易的加入到系统中去,并尽量少的影响其他功能
2.Flexibility灵活性:与扩展性的增加功能相比来,当代码的修改,可以平稳发生,不会波及到其他模块,即与“脆弱”相反
3.Pluggability可插入性:系统设计的接口和实现体,能够满足开发者很方便的替换来修改系统的功能。
从而避免脱离原设计框架的改动方式,进而避免“粘度过高”现象的出现。
即经常出现脱离系统设计框架的“开发捷径”。
设计原则:
1.开闭原则(Open for extension,close for modification)
诚如标题解释的一样:对扩展开放,对修改封闭。在不被修改的情况下扩展,在不被修改的情况下行为产生变化。
对可变性封装的原则:
A.一种可变性不应当散落在很多地方,应该被封装在一个对象里。
B.一种可变性不应该与另一种可变性混合在一起。从这一点上来说,类的继承结构不应该超过2层,不然就意味着2中不同的可变性混合在一起。
这里的2层,我(马背)自己的理解可以解释成具体类实现一个接口的2层,可以可以从继承的角度来看,即从接口-》抽象类-》具体实现类这样的2层“继承”。当然这里的抽象类可以是多级结构,但只是在封装了相同的行为,不影响总体上的2层结构
从2层的结构中我们也可以看出抽象类一定是用来继承的,而具体类则不是用来继承的,并且应该优先使用接口声明类型。
继承应该被看做封装变化的方法,而不是从一般对象到特殊对象的方法。
2.里氏替换原则(Liskov substitution principle)
任何基类被子类替换后,整个应用的功能没有变化(行为产生变化)。
但反过来的代换是不成立的。
由于Liskov替换原则主要讲基类与子类的关系,这里也说一下继承关系使用的条件:
A.区分好子类是不是超类的一个“角色”,即只有"Is-A"的关系才符合。
"Has-A"则应用使用聚合关系描述。
B.子类不会出现成为其他类子类的可能行。
C.子类具体扩展超类的责任,但不是置换掉(Override)或者注销掉(Nullify)超类的责任。
D.从分类学上有意义时候使用继承,不要从工具类继承。
当有继承关系的两个类A、B不符合Liskov原则时候,一般有2中方法来解决:
A.为2者抽象出一个超类,并使二者的共同行为移到新的超类中。
B.把B继承与A改为委派关系,即B拥有A的实例。
未完待续。。。
马背{eric.liu}
2010.1.24