面向对象七大原则
一、单一职责原则
定义:1.一个对象应该只包含单一的职责,并且该职责被完整的封装在一个类中
2.就一个类而言,应该仅有一个引起它变化的原因
分析:1.一个类(或者大到模块,小到方法)承担的职责越多,它被复用的可能性越小,而且如果一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运行
2.类的职责主要包括两个方面:数据职责和行为职责,数据职责通过其属性来体现,而行为职责通过其方法来实现
3.单一职责原则是实现高内聚、低耦合的指导方针,在很多代码重构手法中都能找到它的存在,它是最简单又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关重构经验
总结:一个类只应该有一个引起他变化的原因,不要让一个类拥有多种变化的理由。换句话说,一个类只应该完成和一个职责相关的业务,不要让一个类承担过多的
职责。粒度的大小根据业务来,一般来时候简单的职责可以让一个类兼任,但是复杂的职责,必须独立(高内聚指的就是单一职责原则,一个类职责越单一,内聚度越高)
二、里氏替换原则
定义:1.如果对每一个对象类型为S的对象O1,都有类型为T的对象O2,使得以T定义的所有程序P在所有的对象O1都代还成O2是,程序P的行为没有变化,那么类型S是类型T的子类型
2.所有引用基类(父类)的地方必须能透明的使用其子类的对象
分析:1.在软件中如果能够使用基类对象,那么一定能够使用其子类对象。把基类都替换成它的子类,程序将不会产生任何的错误和异常,反过来则不成立,若果一个软件实体使用的是一个子类的化,那么它不一定能够使用基类
3.里氏替换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象
总结:父类出现的地方,子类一定可以替换,如果父类的方法在子类中不适用,或者在子类中发生畸变,则应该断开父子关系。父类的方法子类无条件继承,很可能导致父类方法在子类中不适用的情况。
三、依赖倒转原则
1.高层模块不应该依赖底层模块,他们都应该依赖抽象。抽象不应该依赖细节,细节应该依赖于抽象
2.要针对接口编程,不要针对实现编程
总结:面向抽象编程,不要面向具体编程。尽量使用抽象耦合代替具体耦合。低耦合指的就是依赖倒置原则
四、开闭原则
一个软件实体应当对扩展开放,并对修改关闭。也就是说在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展,即实现在不修改源代码的情况下改变这个模块的行为。
开闭原则实例:
某图形界面系统提供了各种不同形状的按钮,客户端代码针对这些按钮进行编程,用户可能会改变需求要求使用不同的按钮实现不同的功能,原始设计方案:
图(1)
现对系统重构,使之满足开闭原则:
图(2)
图(1):客户端中的一个方法调用加法类,要想添加一个减法类,就得改变加法类中的代码,使用分支语句实现,违背了开闭原则
图(2):这个图中添加了一个运算父类,这样再添加减法类的时候就不用修改客户端类
开闭原则总结:软件实体应该面向修改关闭,面向扩展开放。其实现的核心就是“抽象”。把相同的代码抽取出来,便于重用,这就是“闭”。把不同的代码也抽取出来,便于功能的扩展,这就是“开”。开闭原则是设计原则的核心原则,其他设计原则都是开闭原则的体现和补充
五、接口隔离原则
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。接口隔离原则有两层含义:(1)客户需要什么样的接口,就提供什么样的接口,不需要的就删除掉;(2)类之间的依赖关系应建立在最小接口上,也就是说接口要尽量的细化,同时接口中的方法应该尽量少,职责要尽可能单一。
当一个接口太大时,我们需要将它分割成多个更小的接口,使用该接口的客户端仅需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色,不干不该干的事。
在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。一般而言,接口中仅包含为某一类用户定制的方法即可,不应该强迫客户依赖于那些它们不用的方法。
六、迪米特法则
迪米特法则又叫最小知识原则,一个软件实体应当尽可能少地与其他实体发生相互作用。迪米特法则是对软件系统中实体之间通信的限制,对实体之间通信的宽度和深度提出了要求。迪米特法则要求当修改系统的某一个模块时,要尽量少地影响其他模块,从而使类与类之间保持松散的耦合关系,使系统扩展相对容易
迪米特法则还有几种定义形式,包括:不要和“陌生人”说话、只与你的直接朋友通信等,在迪米特法则中,对于一个对象,其朋友包括以下几类:
当前对象本身(this);
以参数形式传入到当前对象方法中的对象;
当前对象的成员对象;
如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;
当前对象所创建的对象。
任何一个对象,如果满足上面的条件之一,就是当前对象的“朋友”,否则就是“陌生人”。在应用迪米特法则时,一个对象只能与直接朋友发生交互,不要与“陌生人”发生直接交互,这样做可以降低系统的耦合度,一个对象的改变不会给太多其他对象带来影响。
迪米特法则要求我们在设计系统时,应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度。
在将迪米特法则运用到系统设计中时,要注意下面的几点:在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;在类的结构设计上,每一个类都应当尽量降低其成员变量和成员函数的访问权限;在类的设计上,只要有可能,一个类型应当设计成不变类;在对其他类的引用上,一个对象对其他对象的引用应当降到最低。
七、聚合/组合服用原则
组合复用原则也叫合成/聚合复用原则(CARP),就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新对象通过向这些已有对象委派任务,从而达到复用已有功能的目的。简单的说是,尽量使用对象的组合/聚合(has-a),而不是继承(is-a)来达到复用的目的。
组合/聚合和继承是实现代码复用的两种基本途径,在设计过程中尽量使用组合/聚合,而不是继承。因为继承使得基类与子类有较强的耦合性,通常情况下基类的内部细节对子类来说是可见的,这样基类的实现细节会暴露给子类,破坏了系统的封装性。
总之尽量使用聚合/组合完成代码复用,少用继承复用。继承在java中只能单根继承,不能通过继承实现多个类代码的复用。但是聚合/组合可以。