设计模式的六大原则


1、开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。

简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。



2、里氏代换原则(Liskov Substitution Principle)

英文缩写:

LSP (Liskov Substitution Principle)。是面向对象设计的基本原则之一。


严格的定义:

任何基类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都换成o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。 


通俗的定义:

所有引用基类的地方必须能透明地使用其子类的对象。


更通俗的定义:

子类可以扩展父类的功能,但不能改变父类原有的功能。


里氏替换原则包含以下4层含义:

1. 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。

2. 子类中可以增加自己特有的方法。

3. 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

4. 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。


在我们做系统设计时,经常会设计接口或抽象类,然后由子类来实现抽象方法,这里使用的其实就是里氏替换原则。子类可以实现父类的抽象方法很好理解,事实上,子类也必须完全实现父类的抽象方法,哪怕写一个空方法,否则会编译报错。

里氏替换原则的关键点在于不能覆盖父类的非抽象方法。父类中凡是已经实现好的方法,实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些规范,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。


LSP讲的是基类和子类的关系。只有当这种关系存在时,里氏代换关系才存在。如果两个具体的类A,B之间的关系违反了LSP的设计,(假设是从B到A的继承关系)那么根据具体的情况可以在下面的两种重构方案中选择一种。

-----创建一个新的抽象类C,作为两个具体类的超类,将A,B的共同行为移动到C中来解决问题。

-----从B到A的继承关系改为委派关系。



3、依赖倒转原则(Dependence Inversion Principle)

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。



4、接口隔离原则(Interface Segregation Principle)


这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。


通俗的定义:

·使用多个专门的接口比使用单一的总接口要好。

·一个类对另外一个类的依赖性应当是建立在最小的接口上的。

·一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。

·不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。



5、迪米特法则(Law of Demeter)


英文简写为: LoD

迪米特法则(Law of Demeter)又叫作最少知道原则(Least Knowledge Principle 简写LKP),一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。


通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。



6、合成/聚合复用原则(Composite Reuse Principle, CRP)


合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。


什么是合成?

合成表示一种强的拥有关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样,打个比方:人有两个胳膊,胳膊和人就是部分和整体的关系,人去世了,那么胳膊也就没用了,也就是说胳膊和人的生命周期是相同的

合成关系用实心的菱形+实线来表示


什么是聚合?

聚合表示一种弱的拥有关系,体现的是A对象可以包含B对象,但是B对象并不是A对象的一部分,打个比方:人是群居动物,所以每个人属于一个人群,一个人群可以有多个人,所以人群和人是聚合的关系

聚合关系用空心的菱形+实线来表示 


为什么尽量不要使用类继承而使用合成/聚合?

对象的继承关系在编译时就定义好了,所以无法在运行时改变从父类继承的子类的实现

子类的实现和它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化

当你复用子类的时候,如果继承下来的实现不适合解决新的问题,则父类必须重写或者被其它更适合的类所替换这种依赖关系限制了灵活性,并最终限制了复用性



设计模式的类型


1. 创建型模式

·工厂模式(Factory Pattern)

·抽象工厂模式(Abstract Factory Pattern)

·单例模式(Singleton Pattern)

·建造者模式(Builder Pattern)

·原型模式(Prototype Pattern)


这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用新的运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。


2. 结构型模式

·适配器模式(Adapter Pattern)

·桥接模式(Bridge Pattern)

·过滤器模式(Filter、Criteria Pattern)

·组合模式(Composite Pattern)

·装饰器模式(Decorator Pattern)

·外观模式(Facade Pattern)

·享元模式(Flyweight Pattern)

·代理模式(Proxy Pattern)


这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。


3. 行为型模式

·责任链模式(Chain of Responsibility Pattern)

·命令模式(Command Pattern)

·解释器模式(Interpreter Pattern)

·迭代器模式(Iterator Pattern)

·中介者模式(Mediator Pattern)

·备忘录模式(Memento Pattern)

·观察者模式(Observer Pattern)

·状态模式(State Pattern)

·空对象模式(Null Object Pattern)

·策略模式(Strategy Pattern)

·模板模式(Template Pattern)

·访问者模式(Visitor Pattern)


这些设计模式特别关注对象之间的通信。


4. J2EE 模式

·MVC 模式(MVC Pattern)

·业务代表模式(Business Delegate Pattern)

·组合实体模式(Composite Entity Pattern)

·数据访问对象模式(Data Access Object Pattern)

·前端控制器模式(Front Controller Pattern)

·拦截过滤器模式(Intercepting Filter Pattern)

·服务定位器模式(Service Locator Pattern)

·传输对象模式(Transfer Object Pattern)


这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。


附:

JAVA23种设计模式详解

http://www.runoob.com/design-pattern/design-pattern-tutorial.html


推荐书籍:


注意:本文归作者所有,未经作者允许,不得转载