读了什么书?
人称软件设计三部曲的 《设计模式》《重构》《重构与模式》
《设计模式》:如果一部电影豆瓣评分高达9分,你会不会看?那如果是一本书呢?
深深的感受下amazon关于这本书有用度排名第一的评论:
什么?没看懂!没关系,我是只拿这个来提高这篇文章的逼格用的,不过放心对于这本书几乎清一色的好评。
《重构》:豆瓣评分一样高达9.1分,和《设计模式》一样,
有关于这本书的作者,就多说几句:
福勒(Martin Fowler),在面向对象分析设计、UML、模式、软件开发方法学、XP、重构等方面,都是世界顶级的专家,现为Thought Works公司的首席科学家。Thought Works是一家从事企业应用开发和集成的公司。早在20世纪80年代,Fowler就是使用对象技术构建多层企业应用的倡导者,他著有几本经典书籍:《分析模式》、《UML精粹》和《重构》等。
《重构与模式》:看看为这本书做序的人你就知道这本书为什么值得一看了。
重构是一个动作(小步快跑,持续迭代),模式是一个结果(呈现出合理使用设计模式的架构)
什么是好书?
关于这点我在这两个星期也有点感悟。到底什么是好书!我个人认为:
1. 从0到1,提出新的概念,新的思维,新的方案并成为大众所接受的书。
2. 对实践经验进行全面深刻的总结,并能帮助大众解决实际问题的书。
3. 启发式的书籍,在读的过程中给人一种醍醐灌顶,相见恨晚的感觉,这种书不一定给出具体的解决方案,但会影响读者思考问题的方式。
关键字
开闭
说开闭原则是一切软件设计的终极目标一点也不为过,举个例子就是开闭原则就是宪法,而所有的法律法规的制定都要以宪法内容为基准,反过来如果所有法律法规内容和规范都执行的很好,也就达到了宪法的内容规定。所谓开闭原则指的是:对扩展开放,对修改封闭。如何理解开闭原则?
如果程序中的一处改动就会产生连锁反应,导致一系列相关模块的改动,那么设计就显得特别僵化,开闭原则建议我们应该对系统进行重构,这样以后对系统再进行那样的改动时,就不会导致更多的修改。如果正确地应用开闭原则,那么以后再进行两样的改动时,就只需要添加新的代码,而不必改动已经正常运行的代码。
开闭原则具有两个主要的特征:
1. 对扩展是开放的
这意味关模块的行为是可以扩展的,当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。换句话说,我们可以改变模块的功能。
2. 对于更改是封闭的
对模块行为进行扩展时,不必改动模块的源代码,模块的二进制可执行版本,无论是可链接的库,DLL或者java的.jar文件,都无需改动。
抽象
如何实现开闭原则,关键是抽象。抽象是我们控制软件复杂性的重要手段。
要想达到对更改是封闭的,我们必须面向抽象编程;
要想达到对扩展是开放的,我们必须抽象变化模块;
左边展示了一个简单的不遵循开闭原则的设计。client类和server类都是具体类。client类使用server类,如果我们希望client对象使用另外一个不同的服务器对象,那么就必须要把client类中使用server类的地方 更改为新的服务器类。
右边展示了一个针对上述问题的遵循开闭原则的设计,在这个设计中,clientInterface类是一个拥有抽象成员函数的抽象类。client类使用这个抽象类,然而client类的对象却使用server类的派生类的对象,如果我们希望client对象使用一个不同的服务器类,那么只需要从clientInterface类派生一个新的类,无需对client类做任何改动。这就做到了对扩展开放,对更改封闭。
依赖倒置
据说所说,任何企业的架构归根结底都是按照某种形式的层次分层设计的。最经典的莫过于三层架构的系统,这这种方式下,在表现层实现用户界面,在领域层实现领域逻辑,在数据源层存取数据,这种方式使你可以将复杂的领域逻辑从界面代码中抽取出来,单独放到中间层,用对象加以建模和组织。
如何将企业应用组织成不同的层次?以及这些层次之间如何协同工作?
我觉得最重要策略或至少一定会用到依赖倒置的原则,这个原则恰恰是面向抽象编程以达到开闭原则的重要一步:
依赖原则简单来说:
1.高层模块不应该依赖于低层模块,二者都应该依赖于抽象
2.抽象不应该依赖于细节,细节应该依赖于抽象
上图中高层的policy layer使用了低层的mechanis layer,而mechanism layer又使用了更细节的层utility layer,这看起来似乎是正确的,但是policy layer对于其下一直到utility layer的改动都是敏感的,这种依赖关系是传递的。policy layer依赖于某些依赖于utility layer的层次:因此policy layer传递性地依赖于utility layer。
上图展示了一个更为合适的模型。第一个较高层次都为它所需要的服务声明一个抽象接口,较低的层次实现了这些抽象接口,每个高层类都通过该抽象接口使用下一层,这样高层就不依赖于低层,低层反而依赖于在高层中声明的抽象服务接口。这不仅解除了policy layer对于utility layer的传递依赖关系,甚至也解除了policy layer对于mechanism layer的依赖关系。
委托
一个好的领导不一定知道一件事具体应该怎么做,但一定知道把什么样的事分委托给什么样的人去办,而且委托过程很简单,可能只是一句话,也可能只是面对一个人,就能把事情委托下去并且能办好。程序也是一样,客户端代码对服务或其他函数的调用方法一定是最简洁最明确的,客户端能一行代码完成功能的,绝不用二行代码,能用二行代码完成的,绝不用三行代码,要达到这样的目标必需要对被调用方进行数据封装,逻辑隔离,变化抽象等等,使用到的设计模式包括创建型模式和结构型模式。
委托型的设计模式包括很多:典型的有:
适配器模式
中介者模式
访问者模式
观察者模式
工厂模式
等等等等。。。。太多了, 在我看来,凡是逻辑不是自己实现还是移交给其他类的模式都可以归纳为这类下。
封装
面向对象的三大特性:封装,继承,多态:
如果客户端能简单的调用后台或服务的统一接口,那么类与类之间就必须做好数据与方法的封装:
迪米特原则:
迪米特原则英文全称为Law of Demeter,简称LOD,也称为最少知识原则(Least Knowledge Principle)。虽然名字不同,但描述的是同一个原则:一个对象应该对其他对象有最少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,类的内部如何实现、如何复杂都与调用者或者依赖者没关系,调用者或者依赖者只需要知道他需要的方法即可,其他的我一概不关心。类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
迪米特法则还有一个英文解释是:Only talk to your immedate friends,翻译过来就是:只与直接的朋友通信。什么叫做直接的朋友呢?每个对象都必然会与其他对象有耦合关系,两个对象之间的耦合就成为朋友关系,这种关系的类型有很多,例如组合、聚合、依赖等。
其实涉及到很多的设计模式:
组合模式
解释器模式
策略模式
命令模式
门面模式
等等等等
总结
1.防止过度设计
2.重构一般情况下并不能减少代码量(除了去除重复之外),重构与模式主要目的是使代码易于扩展,易于阅读,结构清晰。
3.不要吝惜去新写一个类。,任何一个复杂的逻辑分支(if,switch)都可以通过新建一个类,使用相关模式进行重构(解释器模式,组合模式,策略模式,命令模式,工厂模式等等)
4.软件是人类有史以来最复杂的系统。其一、软件系统本身规模庞大,参与人手众多,难以管理;其二、环境和需求不断变化,且错误难以避免。人类无法驾驭过于复杂的事物,于是只能寻找方法简化软件系统:把系统分为许多子部分,人们开发一个部分的时候,系统其他部分都是一种抽象,无需了解其细节