CS-Notes/interview/java/设计模式.md
2018-08-29 16:48:52 +08:00

433 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- TOC -->
- [快速理解设计模式](#快速理解设计模式)
- [UML类图术语](#uml类图术语)
- [类的属性的表示方式](#类的属性的表示方式)
- [类的方法的表示方式](#类的方法的表示方式)
- [类和类之间关系的表示方式](#类和类之间关系的表示方式)
- [创建型模式](#创建型模式)
- [单例模式](#单例模式)
- [简单工厂模式](#简单工厂模式)
- [工厂方法](#工厂方法)
- [抽象工厂模式](#抽象工厂模式)
- [建造者(生成器)模式](#建造者生成器模式)
- [原型模式](#原型模式)
- [行为型模式](#行为型模式)
- [责任链模式](#责任链模式)
- [命令模式](#命令模式)
- [解释器模式](#解释器模式)
- [迭代器模式](#迭代器模式)
- [中介者模式](#中介者模式)
- [备忘录模式](#备忘录模式)
- [观察者模式](#观察者模式)
- [状态模式](#状态模式)
- [策略模式](#策略模式)
- [模板方法](#模板方法)
- [访问者模式](#访问者模式)
- [结构型](#结构型)
- [适配器模式](#适配器模式)
- [桥接模式](#桥接模式)
- [组合模式](#组合模式)
- [装饰者模式](#装饰者模式)
- [外观模式](#外观模式)
- [享元模式](#享元模式)
- [代理模式](#代理模式)
- [参考链接](#参考链接)
<!-- /TOC -->
# 快速理解设计模式
设计模式主要分为3大类分别是创建型模式、行为型模式和结构型模式。
# UML类图术语
## 类的属性的表示方式
![](https://images2015.cnblogs.com/blog/617148/201606/617148-20160612221055090-339746853.jpg)
· + 表示public
· - 表示private
· #表示protectedfriendly也归入这类
## 类的方法的表示方式
![](https://images2015.cnblogs.com/blog/617148/201606/617148-20160612222105058-2140837213.jpg)
## 类和类之间关系的表示方式
1、依赖关系
一个类的某个方法引用到了另外一个类,即一个类的调用依赖于另外一个类的定义。
UML表示采用虚线+箭头的方式表示依赖关系
![](https://images2015.cnblogs.com/blog/422101/201609/422101-20160928074646719-2042921908.png)
2、关联关系
体现的是两个类或者类和接口之间语义级别的强依赖关系,它使得一个类知道另外一个类的属性和方法,通常是一个类拥有另外一个类或者接口的成员变量。
UML类图使用普通箭头表示
![](https://images2015.cnblogs.com/blog/422101/201609/422101-20160928074707703-1561044397.png)
3、聚合关系
一种**强**的关联关系聚合是整体和个体之间的关系两个类处于不平等的层次上一个代表整体一个代表局部。体现的是has-a的关系。
UML表示使用空心菱形箭头表示。
![](https://images2015.cnblogs.com/blog/422101/201609/422101-20160928074739125-1256516479.png)
4、组合关系
组合关系也是关联关系的一种,**比聚合关系更强的关系**。组合关系体现的是一种contains-a的关系同样体现的是整体和局部的关系但是整体和局部是不可分的整体的生命周期结束也就意味着部分的生命周期的结束。
UML表示使用实心菱形箭头表示。
![](https://images2015.cnblogs.com/blog/422101/201609/422101-20160928074757360-1817412823.png)
5、实现关系
指的是类和接口之间的关系,一个类实现另外一个接口,实现接口的方法,添加自己的新功能。
UML表示使用虚线+三角形表示
![](https://images2015.cnblogs.com/blog/422101/201609/422101-20160928074410531-1863856350.png)
6、继承关系
指的是类和类之间、接口和接口之间的关系。子类全部继承父类的方法和属性。
UML表示使用实线+三角形表示
![](https://images2015.cnblogs.com/blog/422101/201609/422101-20160928074329344-1140195322.png)
# 创建型模式
创建型模式主要是和创建对象相关的一些设计模式
## 单例模式
目的确保某个类在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类型来决定到底生产哪种具体的产品类
![](img/简单工厂模式.png)
## 工厂方法
目的:工厂方法把类的实例化操作放到子类来执行,本身抽象化。
类图:在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
![](img/工厂方法.png)
## 抽象工厂模式
目的: 抽象工厂模式使用抽象工厂类来产生多个具体的工厂由具体的工厂来生产各自的产品最终关联到抽象产品类中client通过抽象工厂来生产具体的产品。
![](/pics/8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png)
## 建造者(生成器)模式
目的:封装一个对象的构造过程,允许按步骤构造
类图在建造者模式中通过抽象Builder对象来一步步建造
![](/pics/13b0940e-d1d7-4b17-af4f-b70cb0a75e08.png)
例如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;
}
}
```
![](/pics/a40661e4-1a71-46d2-a158-ff36f7fc3331.png)
java.lang.Object#clone()采用的就是原型模式
# 行为型模式
行为型设计模式主要是表示类和对象如何交互,以及如何划分责任和算法。
## 责任链模式
目的:将请求的发送者和接收者解耦,使得多个对象都有处理这个请求的机会。
类图定义一个抽象Handler类实现具体的Handler类来处理请求。
![](/pics/691f11eb-31a7-46be-9de1-61f433c4b3c7.png)
JDK
java.util.logging.Logger#log()
Apache Commons Chain
javax.servlet.Filter#doFilter()
## 命令模式
目的:将命令封装成对象中,以便使用命令来参数化其它对象,或者将命令对象放入队列中进行排队,或者将命令对象的操作记录到日志中,以及支持可撤销的操作。
类图:
![](/pics/ae1b27b8-bc13-42e7-ac12-a2242e125499.png)
JDK
java.lang.Runnable
Netflix Hystrix
javax.swing.Action
## 解释器模式
目的:创建语言的解释器,通常有语言的语法和语法分析来定义
![](/pics/794239e3-4baf-4aad-92df-f02f59b2a6fe.png)
JDK
java.util.Pattern
java.text.Normalizer
All subclasses of java.text.Format
javax.el.ELResolver
## 迭代器模式
目的:提供一种顺序访问对象元素的方法,并且不暴露聚合对象的内部表示
![](/pics/b0f61ac2-a4b6-4042-9cf0-ccf4238c1ff7.png)
## 中介者模式
目的:集中相关对象之间复杂的沟通和控制方式
类图:
- Mediator中介者定义一个接口用于与各同事Colleague对象通信。
- Colleague同事相关对象
![](/pics/d0afdd23-c9a5-4d1c-9b3d-404bff3bd0d1.png)
## 备忘录模式
目的:在不违反封装的情况下获得对象的内部状态,从而在需要的时候可以将对象恢复到最初状态。
类图:
- Originator原始对象
- Caretaker负责保存好备忘录
- Menento备忘录存储原始对象的的状态。备忘录实际上有两个接口一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。
![](/pics/867e93eb-3161-4f39-b2d2-c0cd3788e194.png)
## 观察者模式
目的:定义对象之间的**一对多依赖**,当一个对象状态改变时,它所有依赖都会受到通知并且自动更新状态。
类图:
![](/pics/0df5d84c-e7ca-4e3a-a688-bb8e68894467.png)
JDK
java.util.Observer
java.util.EventListener
javax.servlet.http.HttpSessionBindingListener
RxJava
## 状态模式
目的:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。
类图:
![](/pics/c5085437-54df-4304-b62d-44b961711ba7.png)
## 策略模式
目的:定义一些列算法,封装每个算法,并使他们可以互换。策略模式可以让算法独立于使用它的客户端。
类图:
- Strategy 接口定义了一个算法族,它们都具有 behavior() 方法。
- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior()setStrategy(in Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。
![](/pics/1fc969e4-0e7c-441b-b53c-01950d2f2be5.png)
**与状态模式的比较**
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。
## 模板方法
目的:定义算法框架,并将一些步骤的实现**延迟到子类**。通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
类图:
![](/pics/c3c1c0e8-3a78-4426-961f-b46dd0879dd8.png)
## 访问者模式
目的:为一个对象结构(比如组合结构)增加新能力。
类图:
- Visitor访问者为每一个 ConcreteElement 声明一个 visit 操作
- ConcreteVisitor具体访问者存储遍历过程中的累计结果
- ObjectStructure对象结构可以是组合结构或者是一个集合。
![](/pics/ec923dc7-864c-47b0-a411-1f2c48d084de.png)
# 结构型
结构型模式是用于类或者对象之间的组合关系。
## 适配器模式
目的:把一个类的接口转换成另外一个用户需要的接口
类图:
![](/pics/0f754c1d-b5cb-48cd-90e0-4a86034290a1.png)
## 桥接模式
目的:将抽象和实现分离,可以独立变化
类图:
- Abstraction: 定义抽象类的接口
- Implementor: 定义实现类的接口
![](/pics/c2cbf5d2-82af-4c78-bd43-495da5adf55f.png)
## 组合模式
目的:将对象组合成树形结构来表示“整体/部分”层次关系,允许用户以相同的方式处理单独对象和组合对象。
类图:
![](/pics/3fb5b255-b791-45b6-8754-325c8741855a.png)
JDK:
List
Map
## 装饰者模式
目的:为对象动态添加功能
类图装饰者Decorator和具体组件ConcreteComponent都继承自组件Component具体组件的方法实现不需要依赖于其它对象而装饰者组合了一个组件这样它可以装饰其它装饰者或者具体组件。
![](/pics/137c593d-0a9e-47b8-a9e6-b71f540b82dd.png)
## 外观模式
目的:提供了一个统一的接口,用来访问子系统中的一群接口,从而让子系统更容易使用。
类图:
![](/pics/f9978fa6-9f49-4a0f-8540-02d269ac448f.png)
## 享元模式
目的:利用共享的方式来支持大量细粒度的对象,这些对象的一部分内部状态是相同的。
类图:
- Flyweight享元对象
- IntrinsicState内部状态享元对象共享内部状态
- ExtrinsicState外部状态每个享元对象的外部状态不同
![](/pics/d52270b4-9097-4667-9f18-f405fc661c99.png)
## 代理模式
目的:控制对其他对象的访问。
类图:
![](/pics/a6c20f60-5eba-427d-9413-352ada4b40fe.png)
**代理模式和装饰者模式的区别**
从功能上看,代理模式实现被代理类的简介访问,装饰者模式则是动态添加类的功能
从类图上看,代理类和装饰类均与目标类实现了同一接口,但是代理类拥有真实目标类的成员(关联关系)
# 参考链接
- [JAVA设计模式总结之23种设计模式](https://www.cnblogs.com/pony1223/p/7608955.html)