There should never be more than one reason for a class to change.应该有且仅有一个缘由引发类的变动数据库
换言之,也就是一个接口或类只有一个职责编程
职责的划分很难,要想彻底符合单一职责的设计更难,原则是接口必定要作到单一职责,类的设计尽可能作到只有一个缘由引发变化设计模式
优势架构
缺点函数
If for each object o1 of type S there is an object o2 oftype T such that for all programs P defined in terms of T,the behavior of P is unchanged when o1 issubstituted for o2 then S is a subtype of T.若是对每个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的全部程序P在全部的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。工具
以上是LSP"最正宗"的定义,可是可能不太容易理解,它还有另一种相对清晰明确的定义:性能
Functions that use pointers or references to base classes must be able to useobjects of derived classes without knowing it.全部引用基类的地方必须能透明地使用其子类的对象。设计
通俗点讲,只要父类能出现的地方子类就能够出现,并且替换为子类也不会产生任何错误或异常,使用者可能根本就不须要知道是父类仍是子类。可是,反过来就不行了,有子类出现的地方,父类未必就能适应。(LSP能够正着用但不能反着用)orm
里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含了4层含义:对象
子类必须彻底实现父类的方法
若是子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、汇集、组合等关系代替继承。
覆写或实现父类的方法时输出结果能够被缩小
父类的一个方法的返回值是一个类型T,子类的相同方法(重载或覆写)的返回值为S,那么里氏替换原则就要求S必须小于等于T,也就是说,要么S和T是同一个类型,要么S是T的子类。
在项目中,采用里氏替换原则时,尽可能避免子类的“个性”,一旦子类有“个性”,这个子类和父类之间的关系就很难调和了,把子类当作父类使用,子类的“个性”被抹杀——委屈了点;把子类单独做为一个业务来使用,则会让代码间的耦合关系变得扑朔迷离——缺少类替换的标准。
High level modules should not depend upon low level modules.Both should depend uponabstractions.Abstractions should not depend upon details.Details should depend upon abstractions.
- 高层模块不该该依赖低层模块,二者都应该依赖其抽象;
- 抽象不该该依赖细节;
- 细节应该依赖抽象。
依赖倒置原则在Java中的体现:
更加精简的定义就是“面向接口编程”。
依赖倒置原则的本质就是经过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合,咱们怎么在项目中使用这个规则呢?只要遵循如下的几个规则就能够:
每一个类尽可能都有接口或抽象类,或者抽象类和接口二者都具有
这是依赖倒置的基本要求,接口和抽象类都是属于抽象的,有了抽象才可能依赖倒置
结合里氏替换原则使用
父类出现的地方子类就能出现,再DIP,咱们能够得出这样一个通俗的规则: 接口负责定义public属性和方法,而且声明与其余对象的依赖关系,抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。
依赖倒置原则是6个设计原则中最难以实现的原则,它是实现开闭原则的重要途径,依赖倒置原则没有实现,就别想实现对扩展开放,对修改关闭。在项目中,你们只要记住是“面向接口编程”就基本上抓住了依赖倒置原则的核心。
接口隔离原则有如下两种定义:
Clients should not be forced to depend upon interfaces that they don't use.客户端不该该依赖它不须要的接口。
解释:客户端须要什么接口就提供什么接口,把不须要的接口剔除掉,那就须要对接口进行细化,保证其纯洁性;
The dependency of one class to another one should depend on the smallest possible interface.类间的依赖关系应该创建在最小的接口上。
解释:要求是最小的接口,也是要求接口细化,接口纯洁,与第一个定义一模一样,只是一个事物的两种不一样描述。
归纳:创建单一接口,不要创建臃肿庞大的接口。再通俗一点讲:接口尽可能细化,同时接口中的方法尽可能少。
例如一个接口的职责可能包含10个方法,这10个方法都放在一个接口中,而且提供给多个模块访问,各个模块按照规定的权限来访问,在系统外经过文档约束“不使用的方法不要访问”,按照单一职责原则是容许的,按照接口隔离原则是不容许的,由于它要求“尽可能使用多个专门的接口”。专门的接口指什么?就是指提供给每一个模块的都应该是单一接口,提供给几个模块就应该有几个接口,而不是创建一个庞大的臃肿的接口,容纳全部的客户端访问。
// TODO 仍是感受差不太多...
接口要尽可能小
高内聚具体到接口隔离原则就是,要求在接口中尽可能少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变动的风险也就越少,同时也有利于下降成本。
举例说明:一个用于查询用户的接口,应该提供具体的根据用户ID查询或者根据用户名查询等于业务相关的特定接口,而不是提供一个带有Map(或者说相似Mybatis Example)参数的查询接口
接口设计是有限度的
接口隔离原则是对接口的定义,同时也是对类的定义,接口和类尽可能使用原子接口或原子类来组装。可是,这个原子该怎么划分是设计模式中的一大难题,在实践中能够根据如下几个规则来衡量:
也称为最少知识原则(Least KnowledgePrinciple,LKP)
一个对象应该对其余对象有最少的了解
通俗地讲,一个类应该对本身须要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我不要紧,那是你的事情,我就知道你提供的这么多public方法,我就调用这么多,其余的我一律不关心。
只和朋友交流
迪米特法则还有一个英文解释是:
Only talk to your immediate friends.只与直接的朋友通讯。
一个类只和朋友交流,不与陌生类交流,不要出现getA().getB().getC().getD()这种状况(在一种极端的状况下容许出现这种访问,即每个点号后面的返回类型都相同),类与类之间的关系是创建在类间的,而不是方法间,所以一个方法尽可能不引入一个类中不存在的对象,固然,JDK API提供的类除外。
迪米特法则要求类“羞涩”一点,尽可能不要对外公布太多的public方法和非静态的public变量,尽可能内敛,多使用private、package-private、protected等访问权限。
在实际应用中常常会出现这样一个方法:放在本类中也能够,放在其余类中也没有错,那怎么去衡量呢?你能够坚持这样一个原则:若是一个方法放在本类中,既不增长类间关系,也对本类不产生负面影响,那就放置在本类中。
开闭原则是Java世界里最基础的设计原则,它指导咱们如何创建一个稳定的、灵活的系统
Software entities like classes,modules and functions should be open for extension but closed formodifications.一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
换句话说,一个软件实体应该经过扩展来实现变化,而不是经过修改已有的代码来实现变化。
开闭原则是最基础的一个原则,前面节介绍的五个原则都是开闭原则的具体形态,也就是说前五个原则就是指导设计的工具和方法,而开闭原则才是其精神领袖。换一个角度来理解,依照Java语言的称谓,开闭原则是抽象类,其余五大原则是具体的实现类,开闭原则在面向对象设计领域中的地位就相似于牛顿第必定律在力学、勾股定律在几何学、质能方程在狭义相对论中的地位,其地位无人能及。
抽象约束
何谓元数据?就是用来描述环境和数据的数据,通俗地说就是配置参数,参数能够从文件中得到,也能够从数据库中得到。
封装变化
开闭原则只是精神口号,实现拥抱变化的方法很是多,并不局限于这6大设计原则,可是遵循这6大设计原则基本上能够应对大多数变化。所以,咱们在项目中应尽可能采用这6大原则,适当时候能够进行扩充,例如经过类文件替换的方式彻底能够解决系统中的一些缺陷。你们在开发中比较经常使用的修复缺陷的方法就是类替换,好比一个软件产品已经在运行中,发现了一个缺陷,须要修正怎么办?若是有自动更新功能,则能够下载一个.class文件直接覆盖原有的class,从新启动应用(也不必定非要从新启动)就能够解决问题,也就是经过类文件的替换方式修正了一个缺陷,固然这种方式也能够应用到项目中,正在运行中的项目发现须要增长一个新功能,经过修改原有实现类的方式就能够解决这个问题,前提条件是:类必须作到高内聚、低耦合,不然类文件的替换会引发不可预料的故障。
若是你是一位项目经理或架构师,应尽可能让本身的项目成员稳定,稳定后才能创建高效的团队文化,章程是一个团队全部成员共同的知识结晶,也是全部成员必须遵照的约定。优秀的章程能带给项目带来很是多的好处,如提升开发效率、下降缺陷率、提升团队士气、提升技术成员水平,等等。
在实践中过程当中,架构师或项目经理一旦发现有发生变化的可能,或者变化曾经发生过,则须要考虑现有的架构是否能够轻松地实现这一变化。架构师设计一套系统不只要符合现有的需求,还要适应可能发生的变化,这才是一个优良的架构。
开闭原则是一个终极目标,任何人包括大师级人物都没法百分之百作到,但朝这个方向努力,能够很是显著地改善一个系统的架构,真正作到“拥抱变化”。
首先,不管是6大设计原则仍是23种设计模式,根本目标其实就是一个"拥抱变化",包括需求的变化、运行环境的变化、性能要求的提高等等,实现一个需求并不难,可是当变化来临时,可否泰然处之,那就是个技术活了。
其次,"拥抱变化"落实到代码层面是什么?——你的代码是可维护的、可扩展的,仍是说"牵一发动全身",一点小的改动不少东西都要跟着变更。
再次,要作到"拥抱变化",让你的代码很容易维护和扩展,核心理念就是"高内聚、低耦合",以及"面向接口编程(面向抽象编程)”
最后,设计原则、设计模式是前辈总结的"经验",但不是"条款",尽量遵循这些规范会让你的设计无限接近完美,但世界上本就没有十全十美的东西,凡事都要有个度,不要认死理,不要为了"套模式"而应用设计模式,要具体问题具体分析,根据实际状况进行权衡。
设计作得再漂亮,代码写得再完美,项目作得再符合标准,一旦项目亏本,产品投入大于产出,那总体就是扯淡!
参考文献:《设计模式之禅》