天天看点

面向对象设计原则(三)6. 合成复用原则7. 迪米特原则

合成复用原则又称为聚合复用原则(Composition/Aggregate Reuse Principle, CARP), 其定义如下:

合成复用原则(Composite Reuse Principle, CRP): 尽量使用对象组合, 而不是继承来达到复用的目的

迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。

在迪米特法则运用系统设计中时, 要注意下面的几点, 在类的划分是上, 应当尽量创建松耦合类, 类之间的耦合度越低 就越有利于复用, 一个出在松耦合类一旦被修改, 不会对关联的类造成太大波及; 在类的结构设计上, 每一个类都应当尽量降低其成员变量和成员函数的访问权限; 在类的设计上, 只要有可能, 一个类型应当设计成不变类; 在对其他类的应用上, 一个对象对其他对象的引用应当降到最低.

迪米特法则要求我们在设计系统时, 应该尽量减少对象之间的交互, 如果两个对象之间不必彼此直接通信, 那么这两个对象就不应当发生任何至二级的相互作用, 如果其中也给对象需要调用另外一个对象的某一个方法的话, 可以通过第三者转发这个调用, 简言之. 就是通过引用一个合理的第三者来降低现有对象之间的耦合度

以上的任何一个对象, 都可以当成当前对象的朋友, 否则就是"陌生人", 在应用迪米特法则时, 一个对象只能与至二级朋友发生交互, 不要与"陌生人"直接交互, 这样做可以降低系统的耦合度, 一个对象的改变不会给太多其他对象带来影响

当前对下你给自身(this)

以参数形式传入传入到对象中

当前对象的成员对象

当前对象锁创建的对象

迪米特原则嗨哟集中定义形式: 包括: 不要和"陌生人"说话, 只与你的直接朋友通信等, 子迪米特法则中, 对于一个对象, 其朋友包括以下几类:

如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易,这是对软件实体之间通信的限制,迪米特法则要求限制软件实体之间通信的宽度和深度。迪米特原则可降低系统的耦合度, 使类与类之间保持松散的耦合关系.

迪米特法则来自于1987年美国东北大学(Northeastern University)一个名为“Demeter”的研究项目。迪米特法 则又称为最少知识原则(LeastKnowledge Principle, LKP),其定义如下:

一般而言,如果两个类之间是“Has-A”的关系应使用组合或聚合,如果是“Is-A”关系可使用继承。"Is-A"是严格的分类学意义上的定义,意思是一个类是另一个类的"一种";而"Has-A"则不同,它表示某一个角色具有某一项责 任。

由于组合或聚合关系可以将已有的对象(也可称为成员对象)纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能,这样做可以使得成员对象的内部实现细节对于新对象不可见,所以这种复用又称为“黑箱”复用,相对继承关系而言,其耦合度相对较低,成员对象的变化对新对象的影响不大,可以在新对象中根据实际需要有选择性地调用成员对象的操作;合成复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的其他对象。

通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称“白箱”复用,如果基类发生改变,那么子类的实也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性;而且继承只能在有限的环境中使用(如类没有声明为不能被继承)。

在面向对象设计中, 可以通过两种方法在不同的环境中复用已有的设计和实现, 即通过组合/聚合或通过继承, 但首先应该考虑使用组合/聚合, 组合/聚合可以使系统更加灵活, 降低类与类之间的耦合度, 一个类的变化对其他类造成的影响相对较少; 其次才考虑继承, 使用继承时, 需要严格遵循里式替换原则, 有效使用继承会有助于对问题的理解 降低复杂度, 而滥用继承反而会增阿系统构建和维护的难度以及系统的复杂度 因此需要慎重使用继承复用

合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象, 使之成为新对象的一部分, 新对象通过委派调用已有对象的方法达到复用功能的目的. 简言之: 复用时要尽量使用组合/聚合关系, 少用继承.