我对面向对象的设计原则是最近才开始知道的,今天,于洋同事给我们详细讲了讲面向对象的原则,受益匪浅。我将他的PPT进行了整理和重新排版,希望对软件工程师们有帮助。
面向对象设计主要有以下七大原则:(其中前五大原则更为重要,应用更为广泛)
- 单一职责原则 SRP:Single Responsibility Principle
- 开放封闭原则 OCP,Open Closed Principle
- 依赖倒置原则 DIP,Dependency Inversion Principle
- 里氏替换原则 LSP,Liskov Substitution Pinciple
- 接口隔离原则 ISP,Interface Segregation Principle
- 迪米特法则(Law of Demeter, LoD)又叫最少知识原则(Least Knowledge Principle, LKP)
- 合成/聚合复用原则(Composite/Aggregate Reuse Principle, CARP)也可以简称为合成复用原则(Composite Reuse Principle, CRP)
下面对主要的前五大原则进行详细分析:
1、单一职责原则(Single Responsibility Principle)
SRP定义:对一个类或接口而言,应仅有一个引起它变化的原因。
在SRP中,我们把职责定义为“变化的原因”(a reason for change)。如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多个职责。本原则基本途径就是提高内聚性,如果一个类承担的职责过多,那么这些职责就相互依赖,一个职责的变化可能会影响另一个职责的履行。其实OOD的实质,就是合理的进行类的职责分配。
对于何时遵循SRP有以下考虑:
1、如果应用程序的变化会影响到类中某一种职责,那么就应该将它与另一种职责分离,这样做可以避免客户应用程序和类中的职责耦合在一起。
2、如果应用程序的变化总是会导致两个职责的同时变化,那么就不必分离它们。实际上,分离它们会带来不必要的复杂性。
结论:变化的轴线仅当变化实际发生时才具有真正的意义。如果没有征兆,那么去应用SRP或其他任何原则都是不明智的。
2、开放-封闭原则(The Open-Closed Principle)
OCP:一个软件实体(类、模块、函数等),应该是可扩展的,但是不可修改的。[Software Entities Should Be Open For Extension,Yet Close For Modification]
该原则认为我们应该试图设计出永远也不需要改变的模块。这是理想状态,但我们应该努力最小化不满足OCP原则的模块数量。开放–封闭原则是OOD的真正核心。对扩展开放,模板行为可以被扩展,以满足新的需求;对更改封闭,模块的源代码是不允许改动的。如何做到这两点呢?关键在于抽象;把可能的变化用抽象隔离之。 符合此原则意味着最高等级的复用性(Reusability)和可维护性(Maintainability)。
3、依赖倒置原则(Dependency Inversion Principle)
DIP描述:高层模块不依赖于低层模块,两者都依赖抽象;抽象不应依赖于细节,细节应依赖于抽象。
此原则并非普适于任何上下文,它要求我们把接口(或抽象类)放在使用方(高层),而对被使用方(实现方、低层)透明。 依赖真的要倒置么取决于上下文,接口归属权看谁是系统的核心。
4、里氏替换原则(Liskov Substitution Principle)
LSP描述:使用指向基类(超类)的引用的函数(方法),必须能够在不知道具体派生类(子类)对象类型的情况下使用它们。[ Function Thar Use Referennces To Base(Super) Classes Must Be Able To Use Objects Of Derived(Sub) Classes Without Knowing It ]
简单解释:子类必须能替换成它们的父类 ( Martin )
LSP严格的表达是:如果对每个类型为T1的对象O1,都有类型为T2的对象O2,使得T1定义的所有程序P在所有的对象O1替换成O2的时候,程序的行为没有发生变化,那么类型T2是类型T1的子类型。 LSP是继承复用的基石;它清楚的表示了ISA关系全部都是与行为有关的;所有子类必须符合使用基类的Client所期望的行为;子类型也不得具有比基类更多的限制。
前置条件:每个方法调用之前,该方法应该校验传入参数的正确性,只有正确才能执行该方法,否则认为调用方违反契约,不予执行。这称为前置条件(Pre-condition)。
后置条件:一旦通过前置条件的校验,方法必须执行,并且必须确保执行结果符合契约,这称之为后置条件(Post-condition)。
为了满足LSP,当存在继承关系时,子类中方法的前置条件必须与超类中被覆盖的方法的前置条件相同或者更宽松;而子类中方法的后置条件必须与超类中被覆盖的方法的后置条件相同或者更为严格
违反LSP将使既有的设计不能封闭! LSP原则要求父类应尽可能使用接口或抽象类来实现,即面向接口编程。
5、接口隔离原则(Interface Segregation Principle)
ISP描述:从一个客户类的角度来讲,一个类对另外一个类的依赖性应当是建立在最小的接口上的。使用多个专门的接口比使用单一的总接口要好。 普通的设计师往往想节省接口的数目,将一些功能相关或相近的接口合并,造成接口污染。
从对接口的使用上为我们对接口抽象的颗粒度建立了判断基准:在为系统设计接口的时候,使用多个专门的接口代替单一的胖接口。
今天就介绍到这里。也请大家多多关注。多多指教了。
不错不错,学习学习….
这么经典的总结都让你看到了,呵呵。我认为很有价值的一篇文章。
回访了,谢谢!
回访了,谢谢!