OO设计基本原则

  OO本身就是一种大的设计模式,它是随着软件规模越来越大产生出来帮助人们建模和开发的理念,生来就带着封装、继承、多态等可复用基因。为了充分发挥这些基因的功效,使用者需要遵守一定的原则,就是所谓的面向对象设计原则。然而正确地使用这些运用这些原则并不容易,只有把这些原则吸收成为身体一部分的经验丰富的工程师才能在遇到各种问题时,灵活地使用它们。一些OO大师为了方便新手更好地理解OO原则,就根据经验假象了一些软件设计过程中经常碰到的问题,并给出了遵循OO原则的解决这些问题的设计方案,就产生了设计模式,正如设计模式的定义:设计模式就是我们周围不断重复发生的问题,以及该问题的解决方案的核心【Christopher Alexander】。
        
      OO设计原则是根本,设计模式是设计原则在具体问题中的应用。本文将尝试汇总究竟有哪些OO设计原则,以及它们之间的内在联系。
      首先不得不提著名的SOLID原则:Single responsibility, Open closed, Liskov substitution, Interface segregation, Dependency inversion。
    单一责任原则SRP(Single Responsibility Principle):一个类/对象只有一个引起变化的原因。换言之,一个类只有一个类型责任。(高内聚)
    开放封闭原则OCP(Open Closed Principle):软件实体对扩展开放(对于系统),修改关闭(对于成型模块)。
    里氏替换原则LSP(Liskov Substitution Principle):子类的实例能够替换其父类的实例。基本地说,也就是“子类型必须能够替换掉它们的父类型”。一个软件实体如果运用的是一个父类的话,那          么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。在程序中,把父类都替换成它的子类,程序的行为没有变化.(正方形不是长方形),最有难度的约束设计.
    接口分离原则ISP(Interface Segregation Principle):使用多个专门的接口比使用单一的总接口要好。一个类对另一个的依赖性建立在最小的接口上。
    依赖倒置原则DIP(Dependency Inversion Principle):依赖抽象不要依赖具体实现。(1)高层模块不应该依赖底层模块。两个都应该依赖抽象(2)抽象不应该依赖细节,细节应该依赖于抽象
      其它OO设计原则:
    DRY原则(Don't repeat yourself):避免重复的代码,这样会降低可维护性。
    封装变化原则:把会变化的部分独立出来,让其他部分不受影响。
    组合复用原则:优先使用组合而不是继承,通过获得对其他对象的引用而在运行时刻动态改变对象行为。
    针对接口编程而不是实现:依赖抽象类的接口,可以在运行时改变对象行为,也就是多态。
    迪米特法则LoD(Law of Demeter):也称为最少知识原则LKP(Least Knowledge Principle)。就是说,一个对象应当对其它对象有尽可能少的了解.如果两个类不必彼此直接通信,那么这两个          类就不应当发生直接的相互作用。如果其中一个类须要调用另一个类的某一个要领的话,可以通过第三者转发这个调用。“。它强调我们在封装类的时候,在类的设计结构上,每一个类都          应当降低成员的访问权限。类与类之间的耦合度越低越好,因为一个类被修改,不会对有关联的其他类也执行 修改。(发布-订阅模式),低耦合.
    松耦合原则:对象之间的依赖尽量的少。
    好莱坞原则:别调用我们,我们会调用你。

看到这么多设计原则可能会有些头晕,就像小时候妈妈教我们的做人大道理,宽泛而很难体会,没有经验的工程师只能把他们背下来,在以后的实践过程中慢慢体会。我们可以初步分析一下这些原则的内在联系。
      其中DRY原则松耦合原则,是所有原则的基础,不仅是OO设计的根本,也是所有软件设计的灵魂,我们暂且不归为OO设计原则,应该作为公理存在潜意识中,就像”你要做个好人“。
      封装变化原则,目的是为了提高代码的可维护性,就面向对象设计而言,开放封闭原则就包含了封装变化原则,不仅包含了,跟进一步用扩展的方法来约束变化,所以该原则可以纳入开放封闭原则。
      针对接口编程而不是实现依赖倒置原则很相似,可以说是同一原则的着眼点不同,针对接口编程原则强调的是接口的客户,接口使用者不用关心接口的具体实现;依赖倒置原则强调的是高层模块与底层模块的依赖关系。其实二者是一个原则。
      好莱坞原则依赖倒置原则在框架设计中的一种技巧,可以不作为一个单独的原则。

经过萃取,我们留下了七大面向对象设计原则,他们是:单一责任原则、开放封闭原则、里氏替换原则、接口分离原则、依赖倒置原则、组合复用原则、迪米特法则

※单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。

单一是一个类的优良设计。交杂不清的职责将使得代码看起来特别别扭牵一发而动全身,

有失美感和必然导致丑陋的系统错误风险。

※开放封闭原则:是说软件实体(类、模块、函数等等)应该可以扩展但不可修改。

实现开开放封闭原则的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。

让类依赖于固定的抽象,所以修改就是封闭的;而通过面向对象的继承和多态机制,

又可以实现对抽象类的继承,通过覆写其方法来改变固有行为,实现新的拓展方法,所以就是开放的。

“需求总是变化”没有不变的软件,所以就需要用封闭开放原则来封闭变化满足需求,

同时还能保持软件内部的封装体系稳定,不被需求的变化影响。

※依赖倒置原则:依赖抽象,不要依赖具体。

抽 象的稳定性决定了系统的稳定性,因为抽象是不变的,依赖于抽象是面向对象设计的精髓,

也是依赖倒置原则的核心。依赖于抽象是一个通用的原则,而某些时候依 赖于细节则是在所难免的,

必须权衡在抽象和具体之间的取舍,方法不是一层不变的。依赖于抽象,就是对接口编程,不要对实现编程。

 ※里氏代换原则:子类型必须能够替换到他们的父类型。

Liskov 替换原则,主要着眼于对抽象和多态建立在继承的基础上,因此只有遵循了Liskov替换原则,

才能保证继承复用是可靠地。实现的方法是面向接口编程:将公 共部分抽象为基类接口或抽象类,

通过ExtractAbstractClass,在子类中通过覆写父类的方法实现新的方式支持同样的职责。Liskov替 换原则能够

保证系统具有良好的拓展性,同时实现基于多态的抽象机制,能够减少代码冗余,避免运行期的类型判别。

 ※接口隔离原则:多个和客户相关的接口要好于一个通用接口。

分离的手段主要有以下两种:1、委托分离,通过增加一个新的类型来委托客户的请求,隔离客户和接口的直接依赖,

但是会增加系统的开销。2、多重继承分离,通过接口多继承来实现客户的需求,这种方式是较好的。

下边是前面没有提到过的两个原则,也是设计时要考虑的重要原则。

※迪米特法则:不相互直接通信的类之间,不要直接发生相互作用。

如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果一个类需要调用领一个类的

某个方法话,可以通过第三者转发这个调用。迪米特法则首先强调的前提是在类的设计上,每一类都应当尽量

降低成员的访问权限。它的根本思想是强调类之间的松耦合。

 ※合成/聚合复用原则:尽量使用合成/聚合,尽量不要使用继承。

合 成(Composition)和聚合(Aggregation)都是关联的特殊种类,聚合表示一种弱的拥有关系;

合成这是一种强的拥有关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。

优先使用合成或聚合原则将有助于保持每个类被封装,并被集中在单个任务上。这样类和类继承

层次会保持较小规 模,并且不太可能增长为不可控制的庞然大物。

上一篇:常用的OO设计原则


下一篇:WorldWind源码剖析系列:挂件类Widgets