设计模式六大原则小结

来源:互联网 发布:loadrunner11 java 编辑:程序博客网 时间:2024/06/11 02:42

最近把《设计模式之禅》的设计原则部分看完了,这里对设计模式的六个原则做一个简单的小结

单一职责原则

单一职责原则(Single Responsibility Principle,简称SRP):是指一个类只负责一个功能领域中的相应职责,或者可以定义为,就一个类而言,应该只有一个引起它变化的原因。

单一职责原则其实是从业务角度去考量代码的,他要求一个类只承担一个职责,也就是在设计类的时候要尽可能的解耦,降低类的粒度。尤其是在编写接口的时候,我们一定要做到接口职责的单一,否则未来需求发生变化的时候,接口频繁改动就不好了。但是在考虑实现类的时候,没有必要完全生搬硬套单一职责原则,太多的类不仅会让类间的耦合关系复杂,并且会增加类的数量。也就是说,单一职责原则的核心是对职责的划分,职责划分的越细,类的复杂性就越低,可读性和可维护性都会提高,变更引起的风险降低。但是职责分的很细其实是不现实的,因为职责越细类必然越多,耦合关系越复杂,给技术人员带来的工作量就变多了。所以,实际情况应该根据具体业务判断职责应该划分到什么程度。

值得一提的是,单一职责原则并不只适用于类,也适用于接口,方法等。

开闭原则

开闭原则(Open-Closed Principle,OCP):一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
开闭原则是最重要的面向对象设计原则,它提出我们应该将程序设计足够的可扩展性。因为任何开发工作都需要面临需求变更的问题,并且在需求变更的时候,很多时候我们并不能找到相应代码的原作者去更改代码,即使能找到原作者,说不定也早忘了当初代码的逻辑了。经验表明,修改原来的代码是很容易破坏代码的稳定性的,尤其是在具有复杂耦合关系的代码中,牵一发而动全身。
因此,当需求变更的时候,最好的办法是增加新的代码,而不是去修改既有代码,开闭原则就是遵循这样一个规则的原则。满足开闭原则最关键的是抽象化,通常是先定义一个相对稳定的抽象层,具体的实现细节交给相应的实现类去完成。当某个业务发生变化的时候,可以不必修改现有的业务代码,而只需要增加一个新业务逻辑的实现类即可,这就满足了开闭原则的要求。

里氏替换原则

里氏替换原则(Liskov Substitution Principle, 简称LSP):所有引用基类的地方必须能够透明地使用其子类的对象。

里氏替换原则其实就是针对继承而定的一套规则,说起来就一句话,就是在程序中把一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反之则不一定。要实现这个原则,主要注意以下问题即可:

1.子类必须实现父类中声明的所有方法,为了保证系统的扩展性,在程序中通常使用父类来进行定义,再用子类去实现。子类可以拥有自己的方法,但如果某个方法只存在于子类中,则以父类定义的对象无法使用该方法。在实现父类的方法的时候,为了保证子类覆盖父类不会产生异常,必须要满足两个条件,一是输入的参数范围只能不变或者放大,而是返回的结果只能不变或者缩小。

2.运用里氏替换原则的时候,尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口。这样,在需要扩展系统功能的时候,就无需修改原有子类的代码,只需要新增一个子类就可以了,故里氏替换原则也是实现开闭原则的手段之一。

依赖倒置原则

依赖倒置原则(Dependency Inversion Principle,DIP):抽象不应该依赖于细节,细节应当依赖于抽象,换言之,要针对接口编程,而不是针对实现编程。
依赖倒置原则包含三层含义:
1.高层模块不应该依赖底层模块,两者都应该依赖其抽象
2.抽象不应该依赖细节
3.细节应该依赖抽象
注意,依赖倒置DIP(Dependency Inversion Principle)和依赖注入DI(Dependency Injection)不是一个东西。
DIP的核心观点是通过抽象使各个类或模块的实现彼此独立,不互相影响,从而使各个实现类松耦合。其实DIP要求的开发流程就是在写具体实现之前先拟出一个抽象的框架,框架包含了各个抽象类之间的依赖关系,再往这个抽象框架的各个节点填充具体的实现类。这样的好处就是,每次扩展了一个新的实现类的时候,我的依赖关系依然成立——因为依赖都是在抽象层完成的。即时业务场景变化,某个实现类必须改动,改动的风险也仅仅是这个实现类而已,对抽象类和别的实现类都没有这影响,基本已经是最小的风险了。在抽象层中,建立依赖关系,也就是依赖注入的方式一般有三种。
1.构造函数注入,顾名思义,直接通过构造函数声明依赖对象。
2.Setter方法传递依赖对象,专门写一个setter函数,后台开发中常见的方式。
3.接口声明依赖对象,就是在接口的业务方法中作为参数传进去。

接口隔离原则

接口隔离原则(Interface Segregation Principle,ISP):使用多个专门的接口,而不是使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
接口隔离原则是为了避免冗余接口的出现,因为一旦一个接口包含的功能太多,那么使用这个接口可能就会引进很多不必要的方法,这就违背了接口隔离原则。为了实现这个原则,就要求接口应该尽量的细化,尽量的纯洁。所以我们在编写接口的时候就要建立单一的接口,而不要建立臃肿庞大的接口,接口中的方法应该尽量的少。
它与单一职责原则的区别就是,单一职责原则更多的是在业务逻辑上,认为一个接口只能负担一种职责,但是对接口中的方法并没有要求,也就是一个职责可能会有多个方法并提供给多个模块使用,这违背了接口隔离但是却符合单一职责。接口隔离原则就要求提供给每个模块的接口都应该是单一接口,而不是一整个臃肿的接口。这两个原则其实是有一定冲突的,单一职责原则要求把同一逻辑的功能放在一个接口里,但是接口隔离原则又要求拆分接口,这里面有一个平衡,使在满足单一职责的前提下,接口尽量的小,如何掌握这个度,就是根据经验和常识来判断了。
值得一提的是,这里的接口其实有两种含义。
1.把“接口”理解成一个类型所提供的所有方法特征的集合的时候,这就是一种罗技上的概念了,接口的划分更像是角色的划分,这就意味着需要把大接口划分成不同的角色,一个接口承担一个角色,此时,这个原则可以叫做“角色隔离原则”。
2.把“接口”理解成狭义的特定语言的接口。此时ISP的意思根据方法职责的不同把大接口分成很多个小接口,以确保每个接口使用起来都较为方便,并且承担某一单一角色,每个接口只包含一个客户端所需的方法即可。

迪米特法则

迪米特法则(Law of Demeter,LoD):一个软件实体应当尽可能少地与其他实体发生相互作用。
迪米特法则也称最少知识原则,如果一个系统符合迪米特法则,那么当其中一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易。迪米特法则可降低系统耦合度,使类与类之间保持松散的耦合关系。《设计模式之禅》里对迪米特法则概括出了四点,不过我觉得重要的也就两点。
第一点是类只和朋友交流。朋友大致包括方法参数中的对象,成员对象,当前对象创建的对象和自己,如果当前对象是一个集合,那么集合中的元素也互相为朋友。当前对象便只能和上述几种对象通信,也就是说,如果某个方法内部引入了一个局部对象,这是违反迪米特法则的。除此之外,迪米特法则要求尽量减少对象之间的交流
第二点就是说朋友之间的距离应该尽可能的小。一个对象应该对其他对象有最少的了解,一个类对自己需要耦合或调用的类知道的越少越好,这就要求每个类需要将自己内部的关系良好的隐藏起来,不需要暴露给别人的方法,变量,都应该设置成private。暴露给别人的public方法应该尽量的少。
那么为了减少交流的对象和减少暴露的方法应该做什么呢,A是B的朋友,B又是C的朋友,当A需要C的方法时,就可以通过B间接调用这个方法,而不必和C进行交流,这就减少了交流次数,我们称B为中间类。当系统的依赖关系非常复杂时,用一个中间类统一管理这些依赖关系,可以减少大部分类的“朋友”数量。但是呢,又不能无限制的增加中间类,一般来说,跳转不超过两次是可以接受的,也就是说,只可以有一个中间类。
迪米特法则就是要求类间解耦,但是也不能无限制的解耦下去,粒度太小,对开发也是一种负担,实际应用中,还是需要适度的考虑这些原则。其实设计模式无不遵循这个道理,设计模式是一种思想,而不是定理,过分参考只会“过犹不及”。