一、创建型

1.1 单例模式

原理 : 确保一个类只有一个实例,并提供该实例的全局访问点。

饿汉式 : 静态常量 静态代码块

懒汉式

直接判断(线程不安全) 方法加 synchronized(线程安全, 效率低)

判断后再同步(错误写法)

双重判断(if-同步-if) (推荐写法)

匿名静态内部类 (简单, 推荐)

枚举(简单, 但对象方法写在枚举中, 略有不适)

示例: java.lang.Runtime#getRuntime()java.awt.Desktop#getDesktop()

1.2原型模式

原理 : 使用原型实例指定要创建对象的类型,通过复制这个原型来创建新对象. 示例: JavaObject 对象的 clone 方法, java.util.Arrays.ArrayList#toArray()

浅拷贝 : 仅对基础类型及字符串类型的字段拷贝值

深拷贝 : 同时对引用类型(如数组,对象) 也进行拷贝

深拷贝实现: 1.重写 clone, 一一处理每个引用对象(调用对象的 clone), 麻烦, 且若对象之间关系复杂, 其中一个未实现深拷贝则导致 bug 2.利用序列化和反序列化, 如 Json, 或 Java 自带的序列化方式(二进制)

1.3 创建者模式(生成器模式)

原理 :

封装一个对象的构造过程,并允许按步骤构造.

若对象的生成过于复杂(字段极多且赋值还有依赖关系, 需要顺序调用), 则可将赋值过程封装成一个build(), 并放到一个 Builder 类中. 此类对外提供各个字段的赋值方法并先保存起来, 直到调用 build(), 此方法返回对象实例。

使用此模式, 调用者无需关注构建过程, 只需设置自己想要的值, 然后调用 build() 即可得到对象实例. 且若增加或修改字段, 构造过程变化, 调用者无感知, 无需修改代码. 符合开闭原则。

示例: StringBuilder, 一些框架的 ConfigurationBuilder, 用于构建配置。

1.4 简单工厂模式

原理 : 在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。此模式可避免多个调用者创建对象时判断创建哪个子类的重复代码, 且若多一个子类, 调用者无需修改代码.

示例: Spring ApplicationContextgetBean 方法.

1.5 工厂方法模式

原理 : 定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。 此模式解决了简单工厂每增加一个子类需要修改工厂类的问题。此模式存在问题, 若新增一个子类, 需同时新增一个子类工厂, 系统复杂性更高.

示例: Calendar, NumberFormat

1.6 抽象工厂模式

原理 : 提供一个接口,用于创建 相关的对象家族。同上, 由子类工厂决定创建哪些对象。此模式是工厂方法的升级版, 不同之处在于它同时创建多个种类的对象(工厂类具有多个方法)。

此模式将一个对象家族的新建集合到一个工厂类创建管理, 这些对象家族相互之间一般有关联, 在创建时就可以处理这些关联. 且对于 2 个子类工厂, 一般可以无缝切换, 使得修改代码极为方便(即换一个子类工厂)。

此模式在新增一个对象家族的成员时非常麻烦(即所有工厂类需要新增一个方法), 但再新增一类对象家族时比较简单(即新增一个子类工厂)。


二、结构型

2.1 适配器模式

原理 : 把一个接口转换成另一个用户需要的接口。定义一个类, 实现用户需要的接口, 并聚合一个需要转换的接口对象, 在重写的方法(用户需要的方法)中调用聚合的对象的方法, 若需要返回值, 且返回值类型不一致, 则还需要在方法中处理一番, 然后返回. 这个过程叫做适配.这个类叫做适配器类。使用此模式可对一些老旧接口适配兼容。

示例: java.util.Arrays#asList() 将数组适配成 List, Spring MVCHandlerAdapter

2.2 装饰者模式

原理 :

将一个或多个功能(方法)动态的新增到一个类中。把需要新增功能类称为 A,定义一个类B,实现A的上层接口, 并聚合一个A 的实例对象, B类实现的接口中, 对其他不关心的方法直接调用聚合的对象的方法。对于关心的方法则可以在调用前后进行加料处理(如一个方法返回一个数, 可以在原来的返回值上乘以 2), 同时, B类也可以新增一些其他方法, 这些方法就是多出的功能。B类就是装饰者类, A就是被装饰类。

此模式的优点是, 装饰类也可以当做被装饰类, 然后再来一层装饰, 可以无限的装饰。

示例: java IO

2.3 代理模式

原理 :

控制其他对象的访问(方法级), 将一些前置或后置的处理, 通过代理对象注入到目标对象的方法前后. 面向切面编程.

类型 :

静态代理 : 定义一个代理类实现目标对象的上层接口, 并聚合一个目标对象, 重写方法时将前置后置处理加上.

动态代理 :

JDK 动态代理 : 需要目标对象有上层接口(自然接口内的方法才可以代理) 使用java.lang.reflect.Proxy#getProxyClass

CGLIB动态代理 : 是个类就行。 实现原理是 ASM 框架动态生成目标对象类的子类字节码, 然后通过反射生成代理对象.

示例: Spring AOP

2.4 桥接模式

原理 :

将抽象与实现分离开来,使它们可以独立变化。桥接的含义是, 一个桥, 放在哪里都有桥的 2 边, 桥的 2 边可以变化, 但桥始终不变. 此处, 桥代表一个操作(如手机上运行软件), 2 边代表 一个操作的 2 个维度(如手机和软件). 同时, 桥接后的操作也可以视为一个维度, 与另一个维度桥接(如手机上运行软件和人这 2 个维度, 可以进行桥接, 组成 3 维度嵌套桥接).

示例: JDBC 获取连接, 获取连接是一个维度, 数据库是一个维度, 数据库有多个, 所以这是一个数据库维度变化, 另一维度不变的桥接模式。

2.5 享元模式

原理 :

利用共享的方式来支持大量细粒度的对象,这些对象一部分内部状态是相同的。如常见的 线程池, 常量池等, 使得对象的获取速度加快。

示例: java.lang.Integer#valueOf() java.lang.Boolean#valueOf()

2.6 组合模式

原理 :

将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。一般需要部分和整体具有一定的相似度, 才能对其进行抽象.对部分/整体进行抽象, 得出一个公共抽象类或接口, 再实现类中根据具体角色做不同处理。

示例: java.util.Map#putAll(Map) java.util.List#addAll(Collection)
java.util.Set#addAll(Collection)

2.7 外观模式

原理 :

提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。


三、行为型

3.1 职责链(责任链)模式

原理 : 使多个对象都有机会处理请求,将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止, 从而避免请求的发送者和接收者之间的耦合关系。

示例: javax.servlet.Filter#doFilter()netty 的 Handler Chain

3.2 观察者模式

原理 : 定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

示例: swing 的事件监听(按钮事件, 鼠标事件)、 JS 的 事件监听

3.3 状态模式

原理 : 允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为。

3.4 策略模式

原理 : 定义一系列算法,封装每个算法,并使它们可以互换。策略模式可以让算法独立于使用它的客户端。 策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。

示例: java.util.Comparator#compare()javax.servlet.http.HttpServlet

3.5 模板方法模式

原理: 定义算法框架,并将一些步骤的实现延迟到子类。通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

示例: java.util.Collections#sort()

3.6 命令模式

原理 : 将一个对象(命令接收者)的每个操作拆分到每一个命令类中, 再使用一个命令管理类来管理这些命令。 使得命令可以放入队列中有序执行, 且可以统一记录命令的操作日志, 还可以支持撤销操作(每个命令都实现对应的撤销即可)

此模式的好处是,若将命令抽象为几个标准的命令(如开,关), 然后管理多个命令接收者(如灯,电视机,空调)的操作, 可使新增命令接收者变得简单, 即扩展性好又称万能遥控器。

3.7 中介模式

原理 : 集中相关对象之间复杂的沟通和控制方式。降低子系统之间的耦合。类似一个消息收发中心, 负责字系统的消息中转, 使得子系统之间可以进行一定的交互。

示例: 线程池管理者线程和要执行的任务。

3.8 备忘录模式

原理 : 在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。如对游戏的当前状态进行一个保存, 然后在后续游戏中死亡后可以读取这个状态重新开始。

3.9 访问者模式

原理 : 为一个对象结构(比如组合结构)增加新能力。使用访问者模式可实现重载的动态绑定(即伪双分派), 效果与重载方法内使用 instanceof 是一样的, 但使用访问者模式, 可扩展性更好。

3.10 迭代器模式

原理 : 提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。

示例: java.util.Iterator

3.11 解释器模式

原理 : 为语言创建解释器,通常由语言的语法和语法分析来定义。

示例: EL 表达式, Freemaker模板

3.12 空对象模式

原理 : 使用什么都不做的空对象来代替 NULL, 避免空对象判断, 避免空指针异常。