设计模式概述

一、设计模式的意义

纵观这么多设计模式,其实设计模式的来源就是我们的生活。我们所有的开发无非就是尽量替代人的工作,所以代码之间往往会充满了各种“人性”行为,在日常生活细节中无处不包含着设计模式:

早上出门前,我们要收拾一下自己,再出门,那这个里面就用到了装饰模式。

我们到北京的时候,没有钱买房,自然要租房子,那么最方便的就是通过中介租房,这就是中介者模式。

上班的时候,我们是不是监控服务器的运行情况,如果有问题就报告问题,这就是观察者模式。

…………

类似的情况还有很多,设计源于生活,并服务于生活,使得我们的生活变得很有条理。所以设计模式并不是一个创新性设计,而是将生活中的经典结构用程序设计展示。良好的社会结构服务与我们的生活,使得生活更加便利,同样优秀的设计模式使得我们的程序变得更加井井有条。

下面是23+2种设计模式,在各种的开源框架中,设计模式无处不在,当我们看到代码跳来跳去,最后不知道跳到哪儿的时候,是不是很头疼,其实我们没有理解其中的设计原则,没有抓住核心,使得我们看代码时,看了好多重复、无用的代码。

二、设计模式的分类

创造型模式,共五种:工厂方法模式、抽象工厂模式、单利模式、建造者模式、原型模式

结构型模式,共七种:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、亨元模式

行为型模式,共是一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

其他类:并发型模式、线程池模式

用图形表述为:

M0N@LQ)5IP1AZOLV$67A}UF

三、设计模式的六大原则

1. 开闭原则(Open Close Principle)

顾名思义,就是该开放的就开放,该封闭的就封闭。设计就是为了服务,那么必然后开放接口,但是设计本身是完整的、原子性的,不能说在服务的过程中,我们的设计慢慢的都转型了,变得面目全非。

所以在我们的设计中我们需要设定各种的接口、抽象类,来使保证我们的设计的原子性。

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

这个原则最早在1988年由麻省理工学院的一位姓里的女士(Barbara Liskov)提出来的。

里氏代换原则是面向对象设计的基本原则之一。简单来说,就是项目中所有用到父类的地方都可以替换为子类。因为子类是父类的扩充、完善,父类所有的功能,子类都有,而且更加完善。

看看牛人的解释:

里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:

  • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
  • 子类中可以增加自己特有的方法。
  • 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

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

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

在实际编程中,我们一般需要做到如下3点:

  • 低层模块尽量都要有抽象类或接口,或者两者都有。
  • 变量的声明类型尽量是抽象类或接口。
  • 使用继承时遵循里氏替换原则。

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

要建立单一接口,不要建立庞大臃肿的接口。要尽量细化接口,要为各类建立专用接口,不要试图建立一个什么方法都有的接口让所有类依赖。

采用接口隔离原则对接口进行约束时,要注意以下几点:

  • 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
  • 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
  • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

5. 迪米特法则(Demeter Principle)

迪米特法则又称之最少知道法则。也就是我们常说的高内聚、低耦合。

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

6. 合成复用原则(Composite Reuse Principle)

我们在实现复用的时候,要多用关联,少用继承。

*这个我还理解的不够,需要后续再探索。

7. 单一职责原则

这个就表示职责的原子化,虽然我们没有表将一个职责设定为一个类,但是职责之间要实现隔离,尽量不要在多个职责融合成一个方法。

  • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
  • 提高类的可读性,提高系统的可维护性;
  • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

四、相关优秀的总结

对依赖、关联、聚合和组合之间区别的理解,地址:http://blog.csdn.net/zhengzhb/article/details/7190158

在java中如何准确的体现依赖、关联、聚合和组合。

首先看一看书上对这四种关系的定义:

  • 依赖(Dependency)关系是类与类之间的联接。依赖关系表示一个类依赖于另一个类的定义。例如,一个人(Person)可以买车(car)和房子(House),Person类依赖于Car类和House类的定义,因为Person类引用了Car和House。与关联不同的是,Person类里并没有Car和House类型的属性,Car和House的实例是以参量的方式传入到buy()方法中去的。一般而言,依赖关系在Java语言中体现为局域变量、方法的形参,或者对静态方法的调用。
  • 关联(Association)关系是类与类之间的联接,它使一个类知道另一个类的属性和方法。关联可以是双向的,也可以是单向的。在Java语言中,关联关系一般使用成员变量来实现。
  • 聚合(Aggregation) 关系是关联关系的一种,是强的关联关系。聚合是整体和个体之间的关系。例如,汽车类与引擎类、轮胎类,以及其它的零件类之间的关系便整体和个体的关系。与关联关系一样,聚合关系也是通过实例变量实现的。但是关联关系所涉及的两个类是处在同一层次上的,而在聚合关系中,两个类是处在不平等层次上的,一个代表整体,另一个代表部分。
  • 组合(Composition) 关系是关联关系的一种,是比聚合关系强的关系。它要求普通的聚合关系中代表整体的对象负责代表部分对象的生命周期,组合关系是不能共享的。代表整体的对象需要负责保持部分对象和存活,在一些情况下将负责代表部分的对象湮灭掉。代表整体的对象可以将代表部分的对象传递给另一个对象,由后者负责此对象的生命周期。换言之,代表部分的对象在每一个时刻只能与一个对象发生组合关系,由后者排他地负责生命周期。部分和整体的生命周期一样。

——摘自《Java面向对象编程》,作者:孙卫琴

 

在后续会针对这25种设计模式逐个学习。希望可以在25天给学完。。。

 

参考:

[1] 里氏替换原则:http://blog.csdn.net/zhengzhb/article/details/7281833

[2] 开闭原则:http://blog.csdn.net/zhengzhb/article/details/7296944

[3] 依赖倒转原则:http://blog.csdn.net/zhengzhb/article/details/7289269

[4] 接口隔离原则:http://blog.csdn.net/zhengzhb/article/details/7296921

[5] 迪米特法则:http://blog.csdn.net/zhengzhb/article/details/7296930

[6] 合成复用原则:http://blog.csdn.net/lovelion/article/details/7563441

[7] 单一职责原则:http://blog.csdn.net/zhengzhb/article/details/7278174

[8] 优秀博客:http://blog.csdn.net/u013256816/article/category/5748481 牛叉的很

posted @ 2017-11-20 12:39  wlzjdm  阅读(218)  评论(0编辑  收藏  举报