十分钟了解23种设计模式

注:适用于设计模式入门和面试突击

什么是设计模式?

是经过前人无数次的实践总结出的,设计过程中可以被反复使用的,可以解决特定问题的设计方法,java面向对象编程的所有思想都出自这23种设计模式,无处不用。

1)单例模式(以下几种单例务必掌握):

饿汉式、懒汉式、双重锁(使用volatile防止指令重排)、静态内部类的单例模式(自己封装时最常用)、枚举(最安全的单例)

// 做的补充
JVM在new对象是做了三件事:
        1. 给对象分配内存;
        2. 调用构造函数来初始化成员变量,形成实例;
        3. 将singleton对象指向分配的内存空间。
    JVM在编译器中存在指令重排的优化,第二三步的顺序不能保证。
    volatile防止指令重排。volatile关键字的一个作用是禁止指令重排,把instance声明为volatile之后,对它的写操作就会有一个内存屏障,这样,在它的赋值完成之前,就不用会调用读操作。

2)策略模式:

继承的问题:对类的局部改动,尤其超类的局部改动,会影响其他部分。影响会有溢出效应
策略模式概念:分别封装行为接口,只为了定义规范,不包含逻辑,分离变化部分,封装接口,基于接口编程各种功能。此模式让行为算法的变化独立于算法的使用者。
适用场景:
    1. 几个类的主要逻辑相同,只有部分逻辑的算法和行为稍有区别的情况。
    2. 有几种相似的行为客户端需要动态地决定使用哪种。
一般来说,策略模式不会单独使用,跟模版方法模式、工厂模式等混合使用的情况比较多。

3)工厂模式:

1. 简单工厂模式:
    由一个工厂类根据传入的参数动态判断创建哪个产品类(这些产品类继承自一个父类或接口);
2. 工厂方法模式:
    工厂不再负责产品的创建,由接口针对不同条件返回具体的类实例,由子类决定实例化具体的某一个类。
3. 抽象工厂模式(属于23种设计模式的一种):
    有多个抽象产品类,每个抽象产品类可以派生出多个具体产品类,一个抽象工厂类,可以派生出多个具体工厂类,每个具体工厂类可以创建多个具体产品类的实例。

5)原型模式:

定义:
    通过复制现有的对象实例来创建新的对象实例。
实现方式:
    实现Cloneable接口:
        此接口的作用是在运行时通知虚拟机可以安全地在实现了此接口的类使用clone方法。
    重写Object类中的clone方法(浅拷贝,引用类型指向的还是原对象的地址):
        Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般类无法调用,因此原型需要将clone方法的作用域改为public。
优点:
    1. 使用原型创建一个对象比直接new一个对象更有效率,因为它直接操作内存中的二进制流,特别是复制大对象时性能特别明显。
    2. 隐藏了创建新实例的复杂性,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。
适用场景:
    1. 复制对象的结构和数据。
    2. 希望对目标对象的修改不影响既有的原型对象。
    3. 创建一个对象的成本比较大。

6) 构造器(生成器)模式:

定义:
    将一个复杂对象的构建与它的表示分离,使得同样的构造过程可以创建不同的表示。
优点: 
    1,使用生成器模式可以使客户端不必知道产品内部组成的细节。
    2,具体的建造者类之间是相互独立的,对系统的扩展非常有利。
    3,由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。 

7) 适配器模式:

    将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
优点:
    复用性和扩展性。

8) 外观(门面)模式:

假设系统A内部有多个代码组件,每个代码组件都可以实现一些功能,如果别的系统B要调用系统A实现某个功能,系统A可以对外提供一个Facade类,系统B不需要care系统A内部有多少个代码组件,直接调用A的一个facade类的一个方法即可。
举个例子:service就是一个经典的门面模式。
优点: 
    实现子系统与客户端之间的松耦合关系;
    客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,使得子系统使用起来更加容易。

9) 迭代器模式:

提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。
迭代器是与集合同生共死的,很少自己写迭代,封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历法则不用去关心。

10) 模板方法模式:

使用了java的继承机制,在抽象类中定义了一个模板方法,该方法引用了若干个抽象方法(由子类实现)或具体方法(子类可以覆盖重写)。

11) 中介者模式:

用一个中介者对象封装一系列对象交互,中介者使各对象不需要显示地互相作用,从而使耦合松散,而且可以独立地改变它们之间的交互。
特点:
    比较常用,但也容易被滥用的模式。

12) 代理模式(太常用了:懒加载与远程调用):

为其他对象提供一种代理以控制这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以再客户端和目标对象之间起到中介的作用。
静态代理:
    在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
动态代理:
    动态代理类的源码是程序在运行期间由JVM根据反射等机制动态生成的,所以不存在代理类的字节码文件

13) 观察者模式:

比如我们有一个目标对象,一旦这个目标对象的状态改变了,然后所有依赖于它的对象都会得到通知并自动更新。

14)命令模式:

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,执行不同的命令。
重点:命令模式和策略模式的区别:
    看起来一样的,但是用处不一样。命令是可以发送出去,然后可以经过一些队列的流转,比如先把命令发送到MQ,接着再处理。策略是说选择了一组策略,立即就要执行的,不会经过其他别的什么处理。而且策略逻辑基本就是用在复杂的if else代码中的。

15)组合模式:

可以优化处理递归或分级数据结构,有许多关于分级数据结构的例子,使得组合模式非常有用武之地。

16)状态模式

当系统中某个对象存在多个状态,这些状态之间可与进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化。

17)备忘录模式:

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态。

18) 享元模式:

从最基本的角度来说,其实就是维护固定数量的对象实例,不同的对象实例只有一个,然后保存在内部的一个map中,可以算是跟单例模式的一个扩展和结合吧。
优缺点:
    享元模式的优点在于它大幅度的降低内存中对象的数量,但是它做到这一点所付出的代价也是很高:是系统更加复杂,为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化;享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。

19)装饰者模式:

现有一个可以执行一些功能的类,但还是希望对这个类的功能做一些增强,动态扩展一个对象的功能。
经典实现:IO体系和Spring的AOP,aop这块可以基于动态代理的理念装饰我们的目标对象,加入事务控制、日志打印之类的功能。

20) 责任链模式:

如果你需要动态组装一个业务流程出来,流程中的每个handler业务逻辑需要复用,那就用责任链模式。
优缺点:
    责任链模式与if else相比,他的耦合性要低一些,因为它把条件判定都分散到各个处理类中,比较灵活。

21)桥接模式:

java面向接口编程,无处不桥接,controller、service、dao之间都是使用桥接模式进行编程。
优点:把抽象和实现部分分开,可以灵活的进行单独扩展,还可以动态切换具体的实现。
接口就相当于一座桥,对方的实现是完全透明的。

22) 访问者模式:

是对目标对象动态地执行某个功能,而不对目标对象有任何的改动。

23)解释器模式(很冷门,少用的一种设计模式):

给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。

猜你喜欢

转载自blog.csdn.net/R_P_J/article/details/81107454