2018-08-28 21:10:16 +08:00
|
|
|
|
<!-- TOC -->
|
|
|
|
|
|
|
|
|
|
- [快速理解设计模式](#快速理解设计模式)
|
2018-08-29 16:48:52 +08:00
|
|
|
|
- [UML类图术语](#uml类图术语)
|
|
|
|
|
- [类的属性的表示方式](#类的属性的表示方式)
|
|
|
|
|
- [类的方法的表示方式](#类的方法的表示方式)
|
|
|
|
|
- [类和类之间关系的表示方式](#类和类之间关系的表示方式)
|
2018-08-28 21:10:16 +08:00
|
|
|
|
- [创建型模式](#创建型模式)
|
|
|
|
|
- [单例模式](#单例模式)
|
|
|
|
|
- [简单工厂模式](#简单工厂模式)
|
|
|
|
|
- [工厂方法](#工厂方法)
|
|
|
|
|
- [抽象工厂模式](#抽象工厂模式)
|
|
|
|
|
- [建造者(生成器)模式](#建造者生成器模式)
|
2018-08-29 16:48:52 +08:00
|
|
|
|
- [原型模式](#原型模式)
|
|
|
|
|
- [行为型模式](#行为型模式)
|
|
|
|
|
- [责任链模式](#责任链模式)
|
|
|
|
|
- [命令模式](#命令模式)
|
|
|
|
|
- [解释器模式](#解释器模式)
|
|
|
|
|
- [迭代器模式](#迭代器模式)
|
|
|
|
|
- [中介者模式](#中介者模式)
|
|
|
|
|
- [备忘录模式](#备忘录模式)
|
|
|
|
|
- [观察者模式](#观察者模式)
|
|
|
|
|
- [状态模式](#状态模式)
|
|
|
|
|
- [策略模式](#策略模式)
|
|
|
|
|
- [模板方法](#模板方法)
|
|
|
|
|
- [访问者模式](#访问者模式)
|
|
|
|
|
- [结构型](#结构型)
|
|
|
|
|
- [适配器模式](#适配器模式)
|
|
|
|
|
- [桥接模式](#桥接模式)
|
|
|
|
|
- [组合模式](#组合模式)
|
|
|
|
|
- [装饰者模式](#装饰者模式)
|
|
|
|
|
- [外观模式](#外观模式)
|
|
|
|
|
- [享元模式](#享元模式)
|
|
|
|
|
- [代理模式](#代理模式)
|
|
|
|
|
- [参考链接](#参考链接)
|
2018-08-28 21:10:16 +08:00
|
|
|
|
|
|
|
|
|
<!-- /TOC -->
|
|
|
|
|
|
|
|
|
|
# 快速理解设计模式
|
|
|
|
|
|
|
|
|
|
设计模式主要分为3大类,分别是创建型模式、行为型模式和结构型模式。
|
|
|
|
|
|
2018-08-29 16:48:52 +08:00
|
|
|
|
# UML类图术语
|
|
|
|
|
|
|
|
|
|
## 类的属性的表示方式
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
· + :表示public
|
|
|
|
|
|
|
|
|
|
· - :表示private
|
|
|
|
|
|
|
|
|
|
· #:表示protected(friendly也归入这类)
|
|
|
|
|
|
|
|
|
|
## 类的方法的表示方式
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 类和类之间关系的表示方式
|
|
|
|
|
|
|
|
|
|
1、依赖关系
|
|
|
|
|
|
|
|
|
|
一个类的某个方法引用到了另外一个类,即一个类的调用依赖于另外一个类的定义。
|
|
|
|
|
|
|
|
|
|
UML表示:采用虚线+箭头的方式表示依赖关系
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
2、关联关系
|
|
|
|
|
|
|
|
|
|
体现的是两个类或者类和接口之间语义级别的强依赖关系,它使得一个类知道另外一个类的属性和方法,通常是一个类拥有另外一个类或者接口的成员变量。
|
|
|
|
|
|
|
|
|
|
UML类图:使用普通箭头表示
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
3、聚合关系
|
|
|
|
|
|
|
|
|
|
一种**强**的关联关系,聚合是整体和个体之间的关系,两个类处于不平等的层次上,一个代表整体,一个代表局部。体现的是has-a的关系。
|
|
|
|
|
|
|
|
|
|
UML表示:使用空心菱形箭头表示。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
4、组合关系
|
|
|
|
|
|
|
|
|
|
组合关系也是关联关系的一种,**比聚合关系更强的关系**。组合关系体现的是一种contains-a的关系,同样体现的是整体和局部的关系,但是整体和局部是不可分的,整体的生命周期结束也就意味着部分的生命周期的结束。
|
|
|
|
|
|
|
|
|
|
UML表示:使用实心菱形箭头表示。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5、实现关系
|
|
|
|
|
|
|
|
|
|
指的是类和接口之间的关系,一个类实现另外一个接口,实现接口的方法,添加自己的新功能。
|
|
|
|
|
|
|
|
|
|
UML表示:使用虚线+三角形表示
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
6、继承关系
|
|
|
|
|
|
|
|
|
|
指的是类和类之间、接口和接口之间的关系。子类全部继承父类的方法和属性。
|
|
|
|
|
|
|
|
|
|
UML表示:使用实线+三角形表示
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
2018-08-28 21:10:16 +08:00
|
|
|
|
# 创建型模式
|
|
|
|
|
|
|
|
|
|
创建型模式主要是和创建对象相关的一些设计模式
|
|
|
|
|
|
|
|
|
|
## 单例模式
|
|
|
|
|
|
|
|
|
|
目的:确保某个类在jvm中只有一个实例,提供该实例的全局访问点。
|
|
|
|
|
|
|
|
|
|
类图:使用一个私有构造函数、私有静态变量,和一个共有的静态函数来实现
|
|
|
|
|
|
|
|
|
|
懒汉式(线程不安全)、饿汉式、懒汉式(线程安全)
|
|
|
|
|
|
|
|
|
|
双重校验锁(注意volatile):
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
public class Singleton {
|
|
|
|
|
|
|
|
|
|
private volatile static Singleton uniqueInstance;
|
|
|
|
|
|
|
|
|
|
private Singleton() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Singleton getUniqueInstance() {
|
|
|
|
|
if (uniqueInstance == null) {
|
|
|
|
|
synchronized (Singleton.class) {
|
|
|
|
|
if (uniqueInstance == null) {
|
|
|
|
|
uniqueInstance = new Singleton();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return uniqueInstance;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
为什么要使用volatile?
|
|
|
|
|
uniqueInstance = new Singleton(); 这段代码其实是分三步执行:
|
|
|
|
|
|
|
|
|
|
1. 分配内存空间
|
|
|
|
|
2. 初始化对象
|
|
|
|
|
3. 将 uniqueInstance 指向分配的内存地址
|
|
|
|
|
|
|
|
|
|
JVM的指令重排序可能导致执行顺序编程1-3-2, 在多线程情况下,可能获取一个没有初始化的实例,导致程序出错。
|
|
|
|
|
|
|
|
|
|
使用volatile 可以禁止JVM的指令重排序,保证多线程的环境下程序的正常运行。
|
|
|
|
|
|
|
|
|
|
静态内部类:
|
|
|
|
|
|
|
|
|
|
实现延迟加载,也能实现一次加载,线程安全、相当于同步的懒汉式
|
|
|
|
|
|
|
|
|
|
枚举类型:单例模式的最佳实践,实现简单,并且能在面对复杂的序列化或者反射攻击的时候,能够防止实例化多次。
|
|
|
|
|
|
|
|
|
|
## 简单工厂模式
|
|
|
|
|
|
|
|
|
|
目的:创建对象的时候隐藏内部细节,提供一个创建对象的通用接口。
|
|
|
|
|
|
|
|
|
|
类图:在简单工厂模式中,根据传入type类型来决定到底生产哪种具体的产品类
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 工厂方法
|
|
|
|
|
|
|
|
|
|
目的:工厂方法把类的实例化操作放到子类来执行,本身抽象化。
|
|
|
|
|
|
|
|
|
|
类图:在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 抽象工厂模式
|
|
|
|
|
|
|
|
|
|
目的: 抽象工厂模式使用抽象工厂类来产生多个具体的工厂,由具体的工厂来生产各自的产品,最终关联到抽象产品类中,client通过抽象工厂来生产具体的产品。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 建造者(生成器)模式
|
|
|
|
|
|
2018-08-29 16:48:52 +08:00
|
|
|
|
目的:封装一个对象的构造过程,允许按步骤构造
|
|
|
|
|
|
|
|
|
|
类图:在建造者模式中,通过抽象Builder对象来一步步建造
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
例如JDK中的StringBuilder就是采用建造者模式实现的。
|
|
|
|
|
|
|
|
|
|
## 原型模式
|
|
|
|
|
|
|
|
|
|
目的:使用原型实例指定要创建对象的类型,然后通过复制这个原型来创建新对象,**即通过原型模式创建复杂对象**
|
|
|
|
|
|
|
|
|
|
``` java
|
|
|
|
|
public class ConcretePrototype extends Prototype {
|
|
|
|
|
|
|
|
|
|
private String filed;
|
|
|
|
|
|
|
|
|
|
public ConcretePrototype(String filed) {
|
|
|
|
|
this.filed = filed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
Prototype myClone() {
|
|
|
|
|
return new ConcretePrototype(filed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toString() {
|
|
|
|
|
return filed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
java.lang.Object#clone()采用的就是原型模式
|
|
|
|
|
|
|
|
|
|
# 行为型模式
|
|
|
|
|
|
|
|
|
|
行为型设计模式主要是表示类和对象如何交互,以及如何划分责任和算法。
|
|
|
|
|
|
|
|
|
|
## 责任链模式
|
|
|
|
|
|
|
|
|
|
目的:将请求的发送者和接收者解耦,使得多个对象都有处理这个请求的机会。
|
|
|
|
|
|
|
|
|
|
类图:定义一个抽象Handler类,实现具体的Handler类来处理请求。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
JDK
|
|
|
|
|
|
|
|
|
|
java.util.logging.Logger#log()
|
|
|
|
|
Apache Commons Chain
|
|
|
|
|
javax.servlet.Filter#doFilter()
|
|
|
|
|
|
|
|
|
|
## 命令模式
|
|
|
|
|
|
|
|
|
|
目的:将命令封装成对象中,以便使用命令来参数化其它对象,或者将命令对象放入队列中进行排队,或者将命令对象的操作记录到日志中,以及支持可撤销的操作。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
JDK
|
|
|
|
|
java.lang.Runnable
|
|
|
|
|
Netflix Hystrix
|
|
|
|
|
javax.swing.Action
|
|
|
|
|
|
|
|
|
|
## 解释器模式
|
|
|
|
|
|
|
|
|
|
目的:创建语言的解释器,通常有语言的语法和语法分析来定义
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
JDK
|
|
|
|
|
java.util.Pattern
|
|
|
|
|
java.text.Normalizer
|
|
|
|
|
All subclasses of java.text.Format
|
|
|
|
|
javax.el.ELResolver
|
|
|
|
|
|
|
|
|
|
## 迭代器模式
|
|
|
|
|
|
|
|
|
|
目的:提供一种顺序访问对象元素的方法,并且不暴露聚合对象的内部表示
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 中介者模式
|
|
|
|
|
|
|
|
|
|
目的:集中相关对象之间复杂的沟通和控制方式
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
- Mediator:中介者,定义一个接口用于与各同事(Colleague)对象通信。
|
|
|
|
|
- Colleague:同事,相关对象
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 备忘录模式
|
|
|
|
|
|
|
|
|
|
目的:在不违反封装的情况下获得对象的内部状态,从而在需要的时候可以将对象恢复到最初状态。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|
- Originator:原始对象
|
|
|
|
|
- Caretaker:负责保存好备忘录
|
|
|
|
|
- Menento:备忘录,存储原始对象的的状态。备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 观察者模式
|
|
|
|
|
|
|
|
|
|
目的:定义对象之间的**一对多依赖**,当一个对象状态改变时,它所有依赖都会受到通知并且自动更新状态。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
JDK
|
|
|
|
|
java.util.Observer
|
|
|
|
|
java.util.EventListener
|
|
|
|
|
javax.servlet.http.HttpSessionBindingListener
|
|
|
|
|
RxJava
|
|
|
|
|
|
|
|
|
|
## 状态模式
|
|
|
|
|
|
|
|
|
|
目的:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 策略模式
|
|
|
|
|
|
|
|
|
|
目的:定义一些列算法,封装每个算法,并使他们可以互换。策略模式可以让算法独立于使用它的客户端。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|
- Strategy 接口定义了一个算法族,它们都具有 behavior() 方法。
|
|
|
|
|
- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(in Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
**与状态模式的比较**
|
|
|
|
|
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
|
|
|
|
|
|
|
|
|
|
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。
|
|
|
|
|
|
|
|
|
|
## 模板方法
|
|
|
|
|
|
|
|
|
|
目的:定义算法框架,并将一些步骤的实现**延迟到子类**。通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 访问者模式
|
|
|
|
|
|
|
|
|
|
目的:为一个对象结构(比如组合结构)增加新能力。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|
- Visitor:访问者,为每一个 ConcreteElement 声明一个 visit 操作
|
|
|
|
|
- ConcreteVisitor:具体访问者,存储遍历过程中的累计结果
|
|
|
|
|
- ObjectStructure:对象结构,可以是组合结构,或者是一个集合。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
# 结构型
|
|
|
|
|
|
|
|
|
|
结构型模式是用于类或者对象之间的组合关系。
|
|
|
|
|
|
|
|
|
|
## 适配器模式
|
|
|
|
|
|
|
|
|
|
目的:把一个类的接口转换成另外一个用户需要的接口
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 桥接模式
|
|
|
|
|
|
|
|
|
|
目的:将抽象和实现分离,可以独立变化
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|
- Abstraction: 定义抽象类的接口
|
|
|
|
|
- Implementor: 定义实现类的接口
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 组合模式
|
|
|
|
|
|
|
|
|
|
目的:将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
JDK:
|
|
|
|
|
|
|
|
|
|
List
|
|
|
|
|
Map
|
|
|
|
|
|
|
|
|
|
## 装饰者模式
|
|
|
|
|
|
|
|
|
|
目的:为对象动态添加功能
|
|
|
|
|
|
|
|
|
|
类图:装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 外观模式
|
|
|
|
|
|
|
|
|
|
目的:提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 享元模式
|
|
|
|
|
|
|
|
|
|
目的:利用共享的方式来支持大量细粒度的对象,这些对象的一部分内部状态是相同的。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|
- Flyweight:享元对象
|
|
|
|
|
- IntrinsicState:内部状态,享元对象共享内部状态
|
|
|
|
|
- ExtrinsicState:外部状态,每个享元对象的外部状态不同
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
## 代理模式
|
|
|
|
|
|
|
|
|
|
目的:控制对其他对象的访问。
|
|
|
|
|
|
|
|
|
|
类图:
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
**代理模式和装饰者模式的区别**
|
|
|
|
|
从功能上看,代理模式实现被代理类的简介访问,装饰者模式则是动态添加类的功能
|
|
|
|
|
从类图上看,代理类和装饰类均与目标类实现了同一接口,但是代理类拥有真实目标类的成员(关联关系)
|
|
|
|
|
|
|
|
|
|
# 参考链接
|
|
|
|
|
|
|
|
|
|
- [JAVA设计模式总结之23种设计模式](https://www.cnblogs.com/pony1223/p/7608955.html)
|
|
|
|
|
|