- [快速理解设计模式](#快速理解设计模式) - [UML类图术语](#uml类图术语) - [类的属性的表示方式](#类的属性的表示方式) - [类的方法的表示方式](#类的方法的表示方式) - [类和类之间关系的表示方式](#类和类之间关系的表示方式) - [创建型模式](#创建型模式) - [单例模式](#单例模式) - [简单工厂模式](#简单工厂模式) - [工厂方法](#工厂方法) - [抽象工厂模式](#抽象工厂模式) - [建造者(生成器)模式](#建造者生成器模式) - [原型模式](#原型模式) - [行为型模式](#行为型模式) - [责任链模式](#责任链模式) - [命令模式](#命令模式) - [解释器模式](#解释器模式) - [迭代器模式](#迭代器模式) - [中介者模式](#中介者模式) - [备忘录模式](#备忘录模式) - [观察者模式](#观察者模式) - [状态模式](#状态模式) - [策略模式](#策略模式) - [模板方法](#模板方法) - [访问者模式](#访问者模式) - [结构型](#结构型) - [适配器模式](#适配器模式) - [桥接模式](#桥接模式) - [组合模式](#组合模式) - [装饰者模式](#装饰者模式) - [外观模式](#外观模式) - [享元模式](#享元模式) - [代理模式](#代理模式) - [参考链接](#参考链接) # 快速理解设计模式 设计模式主要分为3大类,分别是创建型模式、行为型模式和结构型模式。 # UML类图术语 ## 类的属性的表示方式 ![](https://images2015.cnblogs.com/blog/617148/201606/617148-20160612221055090-339746853.jpg) · + :表示public · - :表示private · #:表示protected(friendly也归入这类) ## 类的方法的表示方式 ![](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)