为梦而战
全部博文(185)
分类: 架构设计与优化
2015-06-29 16:32:12
把会变化的部分取出并封装起来,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的部分。
好处:代码变化引起的不经意后果变少,系统变得更有弹性。
使用组合建立系统具有很大的弹性,不仅可将算法族封装成类,更可以“在运行时动态地改变行为”,只要组合的行为对象符合正确的接口标准即可。
组合用在“许多”设计模式中。
“针对接口编程”的真正思想是“针对超类型编程”。“针对接口编程”,关键就在多态。利用多态,程序员可以针对超类型编程,执行时会根据实际情况执行到真正的行为,不会被绑死在超类型的行为上。
“针对超类型编程”这句话,可以更明确地说成“变量的声明类型应该是超类型,通常是一个抽象类或者是一个接口,如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量。这也意味着,声明类时不用理会以后执行时真正的对象类型!”
好处:子类实例化的动作不需要在代码中硬编码,而是“在运行时才指定具体实现的对象”。
松耦合的威力:当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。
典型设计模式:观察者模式。
该原则的目标是允许类容易扩展,在不修改先有代码的情况下,就可搭配新的行为。如能实现这样的目标,有什么好处呢?这样的设计具有弹性,可以应对改变,可以接受新的功能来应对改变的需求。
该原则看似矛盾,但是的确有一些技术可以允许在不直接修改代码的情况下对其进行扩展。
在选择需要被扩展的代码部分时,要小心。每个地方都采用开放—关闭原则是一种浪费,也没有必要,还会导致代码变得复杂且难以理解。
遵循开放关闭原则,通常会移入新的抽象层次,增加代码的复杂度。你需要把注意力集中在设计中最有可能改变的地方,然后应用开放—关闭原则。
典型设计模式:装饰者模式。
首先,这个原则听起来很像“针对接口编程,不针对实现编程”,不是吗?的确很相似,然而这里更强调“抽象”。这个原则说明了,不能让高层组件依赖底层组件,而且不管高层组件或低层组件,“两者”都应该依赖于抽象。
举例:
所谓“高层”组件,是有其它底层组件定义行为的类。例如,PizzaStore是个高层组件,因为它的行为是由比萨定义的:PizzaStore创建所有不同的比萨对象,准备、烘烤、切片、装盒;而比萨本身属于底层组件。
在应用工厂方法后,高层组件(PizzaStore)和底层组件(Pizza)都依赖了Pizza抽象。想要遵循依赖倒置原则,工厂方法并非是唯一的技巧,但确实最有威力的技巧之一。
依赖倒置原则倒置在哪里?
在依赖倒置原则中的倒置指的是和一般OO设计的思考方式完全相反。低层组件依赖搞成的抽象。同样地,高层组件也依赖相同的抽象。
依赖倒置原则的指导方针:
1) 变量不可以持有具体类的引用。——如果使用new,就会持有具体类的引用。你可以改用工厂来避开这样的做法。
2) 不要让类派生自具体类。——如果派生自具体类,你就会依赖具体类。请派生自一个抽象类。
3) 不要覆盖基类中已实现的方法。——如果覆盖基类中已实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法应该由所有的子类共享。
注意:以上指导方针应尽量遵守,但并非随时随地必须遵守。
典型设计模式:抽象工厂模式。
最少知识(Least Knowledge)原则告诉我们要减少对象之间的交互,只留下几个“密友”。
最少知识原则:只和你的密友谈话。
当你正在设计一个系统,不管是任何对象,你都要注意他所交互的类有哪些,并注意这些类是如何交互的。
这个原则告诉我们在设计中,不要让太多的类耦合在一起,免得修改系统中一部分,会影响到其它部分。如果许多类之间相互依赖,那么这个系统就会变成一个易碎的系统,它需要花费许多成本维护,也会因为太复杂而不容易被人理解。
如何不要赢得太多的朋友和影响太多的对象?就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:
1) 该对象本身;
2) 被当做方法的参数而传递进来的对象;
3) 此方法所创建或实例化的任何对象;
4) 对象的任何组件。
其中,1)、2)、3)告诉我们,如果对象是调用其它方法的返回结果,不要调用该对象的方法。4)中,可以把“组件”想象成被实例变量所引用的任何对象,换句话说,把这想象成“有一个”(HAS-A)关系。
调用从另一个调用中返回的对象的方法的缺点:相当于向另一个对象的子部分发出请求(而增加我们直接认识的对象数目)。在这种情况下,该原则要我们改为要求该对象为我们作出请求,这么一来,我们就不需要认识对象的组件了(让我们的朋友圈维持在最小的状态)。
最少知识原则的优缺点:虽然这个原则减少了对象之间的依赖,研究显示这会减少软件的维护成本;但是采用这个原则会导致更多的“包装”类被制造出来,已处理和其它组件的沟通,这可能会导致复杂度和开发时间的增加,并降低运行时的性能。
典型设计模式:适配器模式。
好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。
好莱坞原则可以给我们一种防止“依赖腐败”的方法。当高层组件依赖低层组件,而底层组件又依赖高层组件,而高层组件又依赖边侧组件,而边侧组件又依赖低层组件时,依赖腐败就发生了。在这种情况下,没有人可以轻易地搞懂系统是如何设计的。
在好莱坞原则之下,我们允许低层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。换句话说,高层组件对待低层组件的方式是“别调用我们,我们会调用你”。
我们要避免类内的改变,因为修改代码很容易造成潜在的错误。如果一个类具有两个改变的原因,那么这会使得将来该类的变化几率上升,而当它真的改变时,你的设计中同时有两个方面将会受到影响。
类的每个责任都有改变的潜在区域。超过一个责任,意味着超过一个改变的区域。
单一责任原则告诉我们将一个责任只指派给一个类。
要做到这一点的唯一方法,就是努力不懈地检查你的设计,随着系统的成长,随时观察有没有迹象显示某个类改变的原因超过一个。
内聚用来衡量一个类或模块紧密地达到单一目的或责任。当一个模块或一个类被设计成只支持一组相关的功能时,我们说它具有高内聚;反之,当被设计成支持一组不相关的功能时,我们说它具有低内聚。
内聚是一个比单一责任更为普遍的概念,但两者其实关系是很密切的。遵守这个原则的类容易具有很高的凝聚力,而且比背负许多责任的低内聚类更容易维护。