1、写在前面
说起设计模式我想对每一个猿友来说都是一个油腻的话题、23中设计模式张口就来。然而对于这些模式的的设计原则大家还能记起多少?了解多少以及用到多少尼?下面就让我们来一起回顾下。
2、六大设计原则
设计模式六大设计原则分别为、开-闭原则、里氏代换原则、依赖倒转原则、合成/聚合复用原则、迪米特法则、接口隔离原则等六大设计原则。
下面让我们一一介绍下他们吧!
2.1、“开-闭”原则 (ocp)
经典力学的基石是牛顿三大定义、而面向对象可复用设计的第一块基石,便是所谓的“开-闭”原则(open-closed-principle).
什么是“开-闭”原则??????
“开-闭”原则讲的是:一个软件实体应当对扩展开放、对修改关闭(膜拜下 Bertrand Meyer)。
就是说:设计一个模块时、应当使这个模块在不被修改的前提下被扩展。
程序猿语言:应当可以在不必修改源码的情况下改变这个模块的行为。
所有的软件系统有个一共同的特性、即对他的需求会随着时间的推移而改变(当然这不是程序猿大战产品的理由)。
在软件系统面临新的需求时,系统必须是稳如磐石的。
满足“开-闭”原则的设计可以给一个软件系统提供两个无可比拟的优势(少干架)
1: 通过扩展已有软件系统,可以提供新的行为、以满足对软件系统的新需求,使变化中的系统有一定的适应性和灵活性
2: 已有的软件模块、特别是抽象层的模块是万万不能在修改的,这就使变化中的软件系统有一定的稳定性和延续性。
具有这两个优点的软件系统、是一个高层次上实现了复用的系统、也是一个易于维护和扩展的系统。
如何实现“开-闭”原则???
咋看起来、不能修改和可以扩展是相互矛盾的。怎么来实现不能修改的同时用能扩展尼???
解决问题关键还是老生常谈的抽象化了。我们都知道Java语言是一个面向对象的语言,我们可以给系统定一个一个一劳永逸、不再修改的抽象层(或者接口),此设计可以有无穷无尽的行为实现层来实现。
在Java中我们可以抽象出一个或者多个抽象类或者接口、规定出所有具体类(实现类)必须提供的方法特征作为系统设计的抽象层。这个抽象层预见了所有可能的扩展,因此在任何扩展情况下都不会改变。这就使系统的抽象层不需要修改,从而满足“开-闭”原则中的第二条:对修改关闭。
同时、由于从抽象层派生出一个或者多个具体实现类可以改变系统的行为。因此系统的设计对扩展是开放的,这就满足了“开-闭”原则的第一条。
要做到“开-闭”原则不是一件容易的事、但是也不是完全无规律可循、这些规律也同样是以设计原则的身份出现,但是他们都是“开-闭”的手段和工具、是附属于“开-闭”的。
里氏代换原则、依赖倒转原则、合成/聚合复用原则、迪米特法则、接口隔离原则等。
2.2、里氏代换原则(LSP)
从“开-闭”原则中可以看出面向对象设计重要原则是创建抽象化。并且从抽象化导出具体化。
具体化可以给出不同的版本,每一个版本都给出不同的实现(说直白点就是基类和子类的关系)。
从抽象化到具体化的导出要使用到继承关系和这里要引入的里氏代换原则。
什么是里氏代换原则???
一个软件实体如果使用的是一个基类的话,那么一定适用于其子类,而且它根本不能察觉出基类对象和子类对象的区别(也就是说,任何基类出现的地方都可以替换成子类)。
比如: 有两个类,一个是Base类,另一个是Derived类,并且Derived类是Base类的子类。
那么一个方法如果可以接受一个基类对象base的话method(Base base)那么它必然可以接受一个子类对象derived,也就是method(Derived derived)。
注意:里氏代换原则反过来是无法实现的。
2.3、依赖倒转原则(DIP)
实现“开-闭”原则的关键是抽象化、并且从抽象化导出具体实现,如说“开-闭”是面向对象设计的目标的话,依赖倒转原则是面向对象的设计的主要机制。
依赖倒转原则讲的是: 要依赖于抽象,不要依赖于具体。
什么是依赖倒转原则???
简单的说,依赖倒转原则要求客户依赖抽象耦合。
依赖倒转原则表述的是;细节应当依赖于抽象。
其另一种表述是:要针对接口编程,不要针对实现编程,
针对接口编程意思是说,应当使用Java接口和抽象类进行变量的类型声明、参量的类型声明、方法的返回类型声明、以及数据类型的转换等。
不要针对实现编程的意思是说:不应当使用具体类进行变量的类型声明、参量的类型声明、方法的返回类型声明、以及数据类型的转换等。
要保证做到这一点,一个具体的Java 类应当只实现Java接口或者抽象类中声明过的方法,而不应当有多余的方法。
倒转依赖关系强调一个系统内的实体之间的关系的灵活性。基本上,如果设计师希望遵守“开-闭”原则,那么倒转依赖原则便是达到要求的途径。
2.4、接口隔离原则(ISP)
接口隔离原则讲的是:使用多个专门的接口比使用单一总接口要好。换而言之,从一个客户类的角度来讲,一个类对另一个的依赖性应当建立在最小的接口上
什么是接口隔离原则???
使用多个专门的接口比使用单一的总接口要好
一个类对另外一个类的依赖性应当是建立在最小的接口上的。
一个接口代表一个角色,不应当将不同的角色都交给一个接口。
没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。“不应该强迫客户依赖于它们不用的方法。
接口属于客户,不属于它所在的类层次结构。”这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。
2.5、合成/聚合复用原则(CARP)
合成/聚合复用原则经常又叫做合成复用原则。合成/聚合复用原则就是在一个新对象里面使用一个已经存在的对象,使之成为新对象的一部分,新对象通过向这些对象委派达到复用功能的目的。
这个设计原则有另一个更简单的表述: 要进尽量使用合成/聚合,尽量不要使用继承。
合成一词使用比较广泛,经常用易引起混淆。为了避免混淆我们来简单的考察下"合成"和“聚合”的区别
1: 合成和聚合均是关联的特殊种类。
2: 聚合用来表示“拥有”关系或者整体与部分的关系、同时部分可以单独存在。
3: 合成则表示一种强的多的“拥有”关系,部分和整体的生命周期是一致的,部分离开整体无法单独存活的。比如人是一个整体各个肢体是部分。
2.6、迪米特法则(LoD)
迪米特法则又叫最少知道原则,就是说,一个对象应当对其他对象有尽可能少的了解。
迪米特法则最初是用来作为面向对象的系统设计风格的一种法则,1987年秋天由 Ian Holland 在美国东北大学为一个叫迪米特的项目设计提出的。因此叫做迪米特法则。
迪米特法则的各种表述
没有任何一个其它的OO设计原则像迪米特法则这样有如此之多的表述方式,下面是几种有代表性的表述。
1: 只与你直接的朋友通信
2: 不要跟“陌生人”说话
3: 每一个软件单位对其的单位都只有最少的了解,而且局限于哪些与本单位密切相关的软件单位。
在上面表述中里面,什么是“直接“,”陌生“和”密切“则被有意识的模糊化了,以便在不同的环境下可以有不同的解释。
总结
这些设计原则都是软件工程里面很基础也很重要的部分,也是我们开发人员最容易忽略的部分。
作为面试官的几年里,应聘者能完整答上来设计模式的几大原则或者面向对象设计原则的太少了(包括一些高级和资深)。
如果这几大原则没有吃透的话,是不可能设计出一个好的软件系统的。写这篇的目的也在于自己回顾加深一下理解。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。