# designpatterns
**Repository Path**: dr_dark/designpatterns
## Basic Information
- **Project Name**: designpatterns
- **Description**: 设计模式
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2020-09-10
- **Last Updated**: 2021-09-30
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
* [ 21设计模式](#-21%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F)
* [1\. 创建型模式](#1-%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F)
* [ 单例: Singleton ](#-----%E5%8D%95%E4%BE%8B-singleton----)
* [ 普通工厂方法: Factory Method](#-----%E6%99%AE%E9%80%9A%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95-factory-method)
* [ 抽象工厂: Abstract Factory](#-----%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82-abstract-factory)
* [ 建造者: Builder](#-----%E5%BB%BA%E9%80%A0%E8%80%85-builder)
* [ 原型: Prototype](#-----%E5%8E%9F%E5%9E%8B-prototype)
* [2\. 结构型模式](#2-%E7%BB%93%E6%9E%84%E5%9E%8B%E6%A8%A1%E5%BC%8F)
* [桥接: bridge](#%E6%A1%A5%E6%8E%A5-bridge)
* [组合: composite](#%E7%BB%84%E5%90%88-composite)
* [装饰器: Decorator ](#%E8%A3%85%E9%A5%B0%E5%99%A8-decorator-)
* [外观: facade](#%E5%A4%96%E8%A7%82-facade)
* [享元: flyweight](#%E4%BA%AB%E5%85%83-flyweight)
* [代理: proxy](#%E4%BB%A3%E7%90%86-proxy)
* [ 静态代理:](#-%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86)
* [ 动态代理](#-%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86)
* [ cglib代理](#-cglib%E4%BB%A3%E7%90%86)
* [3\. 行为型模式有](#3-%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F%E6%9C%89)
* [责任链: chain of responsibility](#%E8%B4%A3%E4%BB%BB%E9%93%BE-chain-of-responsibility)
* [命令: command](#%E5%91%BD%E4%BB%A4-command)
* [解释器: interpreter](#%E8%A7%A3%E9%87%8A%E5%99%A8-interpreter)
* [迭代器: iterator](#%E8%BF%AD%E4%BB%A3%E5%99%A8-iterator)
* [中介: mediator](#%E4%B8%AD%E4%BB%8B-mediator)
* [备忘录: memento](#%E5%A4%87%E5%BF%98%E5%BD%95-memento)
* [观察者/发布\-订阅模式: observer \-\-\-是一种通知机制](#%E8%A7%82%E5%AF%9F%E8%80%85%E5%8F%91%E5%B8%83-%E8%AE%A2%E9%98%85%E6%A8%A1%E5%BC%8F-observer----%E6%98%AF%E4%B8%80%E7%A7%8D%E9%80%9A%E7%9F%A5%E6%9C%BA%E5%88%B6)
* [状态: state](#%E7%8A%B6%E6%80%81-state)
* [策略: strategy](#%E7%AD%96%E7%95%A5-strategy)
* [模板方法: templatemethod](#%E6%A8%A1%E6%9D%BF%E6%96%B9%E6%B3%95-templatemethod)
* [访问者: visitor](#%E8%AE%BF%E9%97%AE%E8%80%85-visitor)
# 21设计模式
## 1. 创建型模式
### 单例: Singleton
```
项目名: singleton
1. ? : 保证一个类仅有一个实例,并提供一个访问它的全局访问点.
2. 目的: 是为了保证在一个进程中,某个类有且仅有一个实例.
```
```
1.优缺点
优点: 全局只有一个实例,便于统一控制,同时减少了系统资源开销.
缺点: 没有抽象层,扩展困难.
2.应用场景
适合需要做全局统一控制的场景,例如: 全局唯一的编码生成器.
```
### 普通工厂方法: Factory Method
```
项目名:ordinaryfactory
1. ?:定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使一个类的实例化延迟到其子类.
2. 目的:使得创建对象和使用对象是分离的,并且客户端总是引用抽象工厂和抽象产品
```
```
优缺点:
优点: 客户类和工厂类分开.消费者任何时候需要某种产品,只需向工厂请求即可.消费者无须修改就可以接纳新产品.
缺点: 是当产品修改时,工厂类也要做相应的修改.
*/
```
### 抽象工厂: Abstract Factory
```
项目名: abstractfactory
难点: 不但工厂是抽象的,产品是抽象的,而且有多个产品需要创建,因此,这个抽象工厂会对应到多个实际工厂,每个实际工厂负责创建多个实际产品
1. ?: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类.
2. 目的: 为了让创建工厂和一组产品与使用相分离,并可以随时切换到另一个工厂以及另一组产品
```
```
优缺点
优点: 客户类和工厂类分开.消费者任何时候需要某种产品,只需向工厂请求即可.消费者无须修改就可以接纳新产品.
缺点:
1. 不但工厂是抽象的,产品是抽象的,而且有多个产品需要创建,因此,这个抽象工厂会对应到多个实际工厂,每个实际工厂负责创建多个实际产品,
2. 当在抽象工厂在添加一个方法的时候,所有实现抽象工厂的具体方法,都需要添加,
```
### 建造者: Builder
```
项目名: builder
1. ?:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.
2. 目的:使用多个"小型"工厂来最终创建出一个完整对象,如电脑是由 OPU,主板,内存,硬盘,显卡,机箱,显示器,键盘,鼠标等部件组装而成的,客户不可能自己去组装电脑,而是将电脑的配置要求告诉电脑城老板,电脑城老板安排操作人员去组装计算机,操作人员去组好电脑给客户.
```
```
建造者(Builder)模式的主要角色如下.
1. 产品角色(Product): 具体生产的产品,产品有很多零件或者部件组成(零件就是产品的属性),如电脑是由 OPU,主板,内存,硬盘,显卡,机箱,显示器等组成
2. 抽象建造者(Builder): 它是一个包含创建产品各个零件的抽象方法的接口,定义了构建如何组装零件具体操作的接口,同时定义了一个返回产品的方法getProduct
3. 具体建造者(Concrete Builder): 实现 Builder 接口,实现具体完成组装零件具体操作,如电脑装机员(操作员)
4. 指挥者(Director): 它调用构造对象中的具体操作方法完成对象的创建,在指挥者中不涉及具体产品的信息, 如 电脑城的老板指挥装机人员(操作人员)组装电脑调用电脑组装电脑方法,但是并不给出产品
```
```
优点
1.各个具体的建造者相互独立,有利于系统的扩展
2.客户端不必知道产品内部组成的细节,便于控制细节风险.
缺点:
1.产品的组成部分必须相同,这限制了其使用范围
2.产品的内部变化复杂,该模式会增加很多的建造者类
```
### 原型: Prototype
```
项目名: prototype:
1. ?:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
2. 目的:是指创建新对象的时候,根据现有的一个原型来创建
3. 分为浅克隆和深克隆
```
```
浅克隆:
1. 基本类型,复制一份新的值,不和原来对象指向相同的地址,重新开辟一个地址
2. 引用类型,仅仅复制一份引用给新产生的对象,新产生的对象和原来的对象都指向相同的地址,使用共同的属性
prototype\src\cn\design\image\浅拷贝.jpg
深克隆: 对于要克隆的对象, 类对象中 的属性 , 引用一定要实现接口 Cloneable
1. 不管是基本类型还是引用类型,对所有可变(没有被final修饰的引用变量)引用类型的成员变量都开辟新的内存空间,
2. 引用类型和基本类型的引用和原对象的引用都不一样
3. 基于上面原因所以深克隆特别耗时
prototype\src\cn\design\image\深拷贝.jpg
```
```
克隆规范:
.lang.object规范中对clone方法的约定
1.对任何的对象x,都有x.clone() !=x 因为克隆对象与原对象不是同一个对象
2.对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
3.如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立
```
```
克隆的实现:
1. 实现Cloneable接口.在 语言有一个Cloneable接口,它的作用,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法.在 虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常.
2. 重写Object类中的clone方法.所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型
```
```
优缺点:
优点:
1. 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良
2. 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作
缺点:
3. 需要为每一个类都配置一个 clone 方法
4. clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则
5. 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦.因此,深克隆,浅克隆需要运用得当
```
```
---
## 2. 结构型模式有
### 适配器: adapter
```
项目名: adapter
1. 适配器(adapter)模式
2. ?:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作.
3. 目的:将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
4. 适配器有三种模式: 对象适配器 , 类适配器 ,缺省适配模式的结构
重点--> 对象适配器:类的适配器模式把适配的类的API转换成为目标类的API: 这种模式就是我们平时使用spring的时候service层,参看ObjectAdapterClientTest中的调用(链接https://zhuanlan.zhihu.com/p/98718949)
类适配器:与类的适配器模式一样,对象的适配器模式把被适配的类的API转换成为目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类
使用类适配器缺陷很大, 只能实现单继承,多实现有一定的局限性,没有对象适配器灵活
重点--> *缺省适配模式的结构:缺省适配模式是一种"平庸"化的适配器模式,"平庸化"形式可以时所考察的类不必实现不需要的那部分接口
```
```
代码演示:
类适配器: ClassAdapterClientTest
对象适配器: ObjectAdapterClientTest
缺省适配器: DefaultAdapterClientTest
```
```
优点:
1.可以让任何两个没有关联的类一起运行.
2.提高了类的复用.
3.增加了类的透明度.
4.灵活性好.
缺点:
1.过多地使用适配器,会让系统非常零乱,不易整体进行把握.
2. 不能多继承,所以目标类最好是抽象类或者接口
```
## 2. 结构型模式
### 桥接: bridge
```
在理解这个bridge模式的时候参考了 https://www.jianshu.com/p/c71562c98258 感觉能够说明白一点
```
```
项目名: builder
1. ?:将抽象部分与它的实现部分分离,使它们都可以独立地变化.
2. 目的:用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合
```
```
角色
1. Abstraction:抽象类,抽象部分的接口,通常在这个对象里面,要维护一个实现部分的对象引用,在抽象对象里面的方法,需要调用实现部分的对象来完成,这个对象里面的方法,通常都是跟具体的业务相关的方法,
2. RefinedAbstraction:扩充抽象类,扩展抽象部分的接口,通常在这些对象里面,定义跟实际业务相关的方法,这些方法的实现通常会使用Abstraction中定义的方法,也可能需要调用实现部分的对象来完成,
4. Implementor:实现类接口,定义实现部分的接口,这个接口不用和Abstraction里面的方法一致,通常是由Implementor接口提供基本的操作,而Abstraction里面定义的是基于这些基本操作的业务方法,也就是说Abstraction定义了基于这些基本操作的较高层次的操作,
5. ConcreteImplementor:具体实现类,真正实现Implementor接口的对象
```
```
优缺点
优点:
1.由于抽象与实现分离,所以扩展能力强
2.其实现细节对客户透明
缺点:
1.由于聚合关系建立在抽象,要求开发者针对抽象化进行设计和编程,这增加了系统的理解和设计难度
```
### 组合: composite
```
项目名: composite
1. ?:将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性.
2. 目的:使用Composite可以把一个叶子节点与一个父节点统一起来处理.
3. 特点是是: 部分-整体
4. 如hashMap就是组合模式,如电脑中文件夹(包含文件夹和文件)
```
```
优缺点:
优点:
1. 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易
2. 组合模式后,,如果想增加一个子节点的话(类似于ImageFile),只要找到它的父节点(类似File)就成,非常容易扩展,符合开闭原则,对以后的维护非常有利
缺点:
1.使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联
```
```
使用场景:
1. 维护和展示部分-整体关系的场景,如树形菜单,文件和文件夹管理.
2. 从一个整体中能够独立出部分模块或功能的场景.
注意事项:
只要是树形结构,就要考虑使用组合模式,这个一定要记住,只要是要体现局部和整体的关系的时候,而且这种关系还可能比较深,考虑一下组合模式吧
```
### 装饰器: Decorator
```
项目名: decorator
装饰模式又称包装模式(Decorator)--要区别适配器模式,
1. ?:动态地给一个对象添加一些额外的职责.就增加功能来说,相比生成子类更为灵活
2. 目的:在运行期动态给某个对象的实例增加功能的方法
3. 在Jdk 中 InputStream ,OutputStream ,FileInputStream 就是使用的修饰模式
```
```
角色
1.抽象构件角色(Component):给出一个抽象接口,已规范准备接收附加责任的对象,---如 一个 衣服的抽象构件接口
2.具体构件(ConcreteComponent):定义一个将要接收附加责任的类,---即是具体的构件,如衣服构件
3.装饰角色(Decorator):有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口.---一个抽象的修饰类,并且实现了抽象构件接口,衣服的修饰物
4.具体装饰(ConcreteDecorator):负责给构件对象"贴上"附加的责任 ----具体的修饰类,继承 抽象的修饰类,比如: 胸针,纽扣
```
```
优缺点:
1. 在对于扩展的时候,装饰模式比继承更加灵活
缺点:
1. 在多过的装饰层中,会显得特别复杂
```
```
要区别与适配器模式,他们都叫包装模式,
但是
1. 适配器 目的是将一个接口转换为另一个接口,达到接口复用的效果
2. 装饰模式 不改变原来的对象,而是保持原有接口,目的是增强原对象的功能或者是改变原有对象的处理方式而达到提供性能操作
```
### 外观: facade
```
项目名:facade
1. ?:为子系统中的一组接口提供一个一致的界面.Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
2. 目的: 如果客户端要跟许多子系统打交道,那么客户端需要了解各个子系统的接口,比较麻烦.如果有一个统一的"中介",让客户端只跟中介打交道,中介再去跟各个子系统打交道,对客户端来说就比较简单.所以Facade就相当于搞了一个中介
```
```
优缺点:
1. 客户端不用一一访问子系统,只需要访问其"中介",使其对客户端屏蔽子系统,降低客户类与子系统类的耦合度.
2. 外观模式的目的在于降低系统的复杂程度,所有子系统都在外观模式类中执行操作
3. 对客户类提供一个统一的接口
缺点:
4. 不能很好地限制客户使用子系统类,如果客户类对子系统做出限制的话,回大大降低灵活性和可变性
5. 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了"开闭原则".
```
### 享元: flyweight
```
项目名称: flyweight
1. ?:运用共享技术有效地支持大量细粒度的对象,注意这里是细粒度对象
2. 目的: 为避免在创建多个相同对象时,所产生的不必要的资源消耗,使用一个缓存池,存储对象,
```
```
Flyweight(抽象享元类): 通常是接口或抽象类,抽象享元类中声明了具体享元类公共方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)
ConcreteFlyweight(具体享元类): 继承抽象享元类,在具体享元类中为内部状态提供存储空间.通常可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象
UnshareConcreteFlyweight(非分享具体享元类): 并不是所有的具体享元类都需要被共享,不能被共享的子类可以设计为非共享具体享元类,当需要一个非共享具体享元类的对象时可以直接通过实例化创建,在项目如 heroName
FlyweightFactory(享元工厂类): 创建并管理享元对象,将各种具体享元类存储到一个享元池中,享元池一般为"键值对"集合,可以结合工厂模式进行设计.当用户请求一个具体享元对象时,享元池中如果保存的有就直接返回给用户,如果没有就创建该享元对象返回给用户并存储到享元池中
```
```
优缺点:
1.能够极大的减少系统中的对象的个数
2.外部状态相对立,不会影响内部状态,能够使用享元对象在不同环境被共享
缺点:
1.需要区分内部状态和外部状态,使得程序在某种程度上来说更加复杂了
```
### 代理: proxy
```
项目名:proxy
1. ?:为其他对象提供一种代理以控制对这个对象的访问
2. 目的: 通过引入代理对象的方式来间接访问目标对象,这样可以在不修改原目标的前提下,提供额外的功能操作,扩展目标对象功能
```
```
角色:
1. Subject: Subject角色定义了使proxy和realsubject角色之间具有一致性的接口,这个接口提供了一个使用的好处,就是client不必却分它使用的是代理对象还是真实对象
2. Proxy: Proxy角色会尽量处理来自Client角色的请求,只有当自己不能处理的时候,就交给工作交给真实对象,代理对象只有在有必要时才会生成真实的对象,同时实现了Subject解决的接口,
3.RealSubject: 就是实际完成工作的对象
```
```
区别于适配器模式:
这里要区分一下
1. 适配器模式: 适配器是把 B 接口 转换为 A接口,适配器做的事(适配器的代码中是:我需要一个电压,适配器将中国电压转化成美国/德国电压),做的事都产生了变化
2. 而代理模式: 它还是是 A 接口,给调用A接口的时候包了一层,它做的事(这里是买口红),还是不变的(还是买口红),只是不是"我"去做,而是代理对象对做
```
```
优缺点:
优点:
1. 客户端和目标对象之前有一个保护作用
2. 代理对象可以扩展目标对象功能
3. 在一定程度上降低了耦合度,提高了扩展性
缺点:
1. 客户端和真实主题之间增加了代理对象,因此会造成请求的处理速度变慢
2. 实现代理模式需要额外的工作(有些代理模式的实现非常复杂),从而增加了系统实现的复杂度
```
```
关于代理的广泛应用:
1.远程代理
远程代理即Remote Proxy,本地的调用者持有的接口实际上是一个代理,这个代理负责把对接口的方法访问转换成远程调用,然后返回结果, 内置的RMI机制就是一个完整的远程代理模式,
2.虚代理
虚代理即Virtual Proxy,它让调用者先持有一个代理对象,但真正的对象尚未创建,如果没有必要,这个真正的对象是不会被创建的,直到客户端需要真的必须调用时,才创建真正的对象,JDBC的连接池返回的JDBC连接(Connection对象)就可以是一个虚代理,即获取连接时根本没有任何实际的数据库连接,直到第一次执行JDBC查询或更新操作时,才真正创建实际的JDBC连接,
3.保护代理
保护代理即Protection Proxy,它用代理对象控制对原始对象的访问,常用于鉴权,
4.智能引用
智能引用即Smart Reference,它也是一种代理对象,如果有很多客户端对它进行访问,通过内部的计数器可以在外部调用者都不使用后自动释放它
```
#### 静态代理:
```
项目中的StaticProxyClientDemo调用的就是静态代理方法
其缺点:
冗余: 由于目标对象和代理对象实现一致接口,就会产生很多代理类
不易维护: 一旦抽象接口增加方法,目标对象和代理对象都要进行修改
```
```java
public interface Subject {
String bugLipstick(String name);
}
```
```java
public class RealSubject implements Subject {
@Override
public String bugLipstick(String name) {
return "买到了一只" + name + "口红";
}
}
```
```java
public class Proxy implements Subject {
public Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public String bugLipstick(String name) {
//这里通过一些列代码逻辑,...... 得到一个结果
System.out.println("代购获得了" + name + "口红");
return subject.bugLipstick(name);
}
}
```
```java
public class StaticProxyClientDemo {
public static void main(String[] args) {
//故事背景
//女朋友过生,你要买一只阿玛尼的正品(不可能买赝品吧)给你女朋友
// 不知道哪里可以买,但是你知道有代沟
//所以你找代购买了一只阿玛尼的正品口红
//1. 定义你要做的事情(目标对象): 买阿玛尼口红
Subject subject = new RealSubject();
//2. 告诉代购我需要(代替)你帮我做什么
Proxy proxy = new Proxy(subject);
//3. 获得口红
String result = proxy.bugLipstick("阿玛尼");
System.out.println(result);
}
}
```
#### 动态代理
```
项目中的 JdkMoveProxyClientDemo就是动态代理方法实现
1.实现: 利用了JDK API 实现的 动态的在内存中构建对象,从而实现对目标的代理功能, 动态代理又称为 JDK代理和接口代理,
2.涉及到的类 .lang.reflect.Proxy 和 .lang.reflect InvocationHandler
3. 与静态代理的区别:
静态代理在编译时就已经实现了,编译完成后代理类是一个实际的Class文件
动态代理是在运行时动态生成的,即编译完成没有实际的class文件,而是在运行时动态生成字节码,并加载到jvm中
4.特点:动态代理对象不需要实现接口,但是目标对象必须实现接口,否则无法生成代理对象
5.限制: 目标对象必须实现接口,否则无法生成代理对象
```
```java
public class JdkProxy {
/*
* 抽象接口: 声明我(真实对象)需要代购(代理对象)帮忙做(替真实对象对象做)的事情
* 就是我们的目标对象
* 这里写成 Object 为了能够共用
*/
private Object targetObject;
public JdkProxy(Object targetObject){
this.targetObject = targetObject;
}
/*
* @description 通过 .lang.reflect.Proxy 和 .lang.reflect InvocationHandler 实现
* 为目标对象(这里是 targetObject)生成代理对象
* Proxy.newProxyInstance 和 new InvocationHandler()
* @return
* @date 2020/9/23 12:04
*/
public Object getNewInstance(){
return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), this.targetObject.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//只有在真正执行方法的时候才调用
System.out.println("开始执行targetObject方法......");
//执行目标对象的方法
Object object = method.invoke(targetObject, args);
System.out.println("结束执行targetObject方法.....");
//代理对象返回的结果
return object;
}
});
}
}
```
```java
public class JdkMoveProxyClientDemo {
public static void main(String[] args) {
//故事背景
//女朋友过生,你要买一只阿玛尼的正品(不可能买赝品吧)给你女朋友
// 不知道哪里可以买,但是你知道有代沟
//所以你找代购买了一只阿玛尼的正品口红
//定义你要做的事情(目标对象): 买阿玛尼口红
Subject targetObject = new RealSubject();
System.out.println("输出目标对象: "+targetObject.getClass());
//生成一个代理对象
Subject proxy = (Subject) new JdkProxy(targetObject).getProxyInstance();
System.out.println("输出代理对象: "+proxy.getClass());
System.out.println("开始执行代理方法......");
//然后执行代理的方法
String result = proxy.bugLipstick("阿玛尼");
System.out.println(result);
/*
输出结果:
=================================
输出目标对象: class cn.design.realize.RealSubject
输出代理对象: class com.sun.proxy.$Proxy0
开始执行代理方法......
开始执行targetObject方法......
结束执行targetObject方法.....
买到了一只阿玛尼口红
=================================
结论: 动态代理是在正在执行的时候才去调用
*/
}
}
```
#### cglib代理
```
项目中的 CglibProxyClientDemo 就是cglib代理方法实现
1.实现: 是一个第三方类库,运行时在内存中动态生成一个子类对象从而实现对目标对象的扩展功能
2.涉及到的类net.sf.cglib.proxy.MethodInterceptor和net.sf.cglib.proxy.Enhancer
3. 与动态代理的区别:
(1) 动态代理的目标对象必须至少实现一个接口
(2) cglib代理的目标对象无需实现接口,达到代理类无入侵
4.特点;
(1)CGLIB是一个强大的高性能的代码生成包,它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)
(2)CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类
5. maven 依赖:
cglib
cglib
2.2或者其他版本
```
目标对象
```java
public class OtherRealSubject {
/*
* @param name
* @return .lang.String
* @description 我想要做的事是: 买一只口红 ,Lipstick:口红
* @author dlq
* @date 2020/9/23 9:52
*/
public String bugLipstick(String name) {
return "买到了一只" + name + "口红";
}
}
```
代理对象生成
```java
public class CglibProxy implements MethodInterceptor {
/**
* 抽象接口或者具体接口: 声明我(真实对象)需要代购(代理对象)帮忙做(替真实对象对象做)的事情
* 就是我们的目标对象
* 这里写成 Object 为了能够共用
*/
private Object targetObject;
public CglibProxy(Object targetObject) {
this.targetObject = targetObject;
}
/**
* @description 为目标对象生成代理对象
* @param
* @return .lang.Object
* @date 2020/9/23 14:30
*/
public Object getProxyInstance(){
//工具类
Enhancer enhancer = new Enhancer();
//设置父类,也就是我们的目标对象,作用是扩展这个targetObject对象
enhancer.setSuperclass(targetObject.getClass());
//设置回调函数
enhancer.setCallback(this);
//回调(如果有)以创建新的对象实例
return enhancer.create();
}
/*
* @description intercept 这个方法是在 代理对象具体调用方法的时候,再调用的
* @param o
* @param: method
* @param: objects
* @param: methodProxy
* @return .lang.Object
* @date 2020/9/23 14:31
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理----开始执行targetObject方法......");
Object resultValue = method.invoke(targetObject,objects);
System.out.println("cglib代理----结束执行targetObject方法.....");
return resultValue;
}
}
```
```java
public class CglibProxyClientDemo {
public static void main(String[] args) {
//故事背景
//女朋友过生,你要买一只阿玛尼的正品(不可能买赝品吧)给你女朋友
// 不知道哪里可以买,但是你知道有代沟
//所以你找代购买了一只阿玛尼的正品口红
//定义你要做的事情(目标对象): 买阿玛尼口红
OtherRealSubject targetObject = new OtherRealSubject();
System.out.println("输出目标对象: "+targetObject.getClass());
///生成一个代理对象
OtherRealSubject proxy = (OtherRealSubject) new CglibProxy(targetObject).getProxyInstance();
System.out.println("输出代理对象: "+proxy.getClass());
System.out.println("开始执行代理方法......");
//然后执行代理的方法
String result = proxy.bugLipstick("阿玛尼");
System.out.println(result);
/*
输出结果:
=================================
输出目标对象: class com.example.demo2.proxydemo.OtherRealSubject
输出代理对象: class com.example.demo2.proxydemo.OtherRealSubject$$EnhancerByCGLIB$$21115223
开始执行代理方法......
cglib代理----开始执行targetObject方法......
cglib代理----结束执行targetObject方法.....
买到了一只阿玛尼口红
=================================
结论: 和动态代理一样,是在正在执行代理对象调用的时候才去调用
*/
}
}
```
---
## 3. 行为型模式有
### 责任链: chain of responsibility
```
项目名: chainofresponsibility
1. ?:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链:当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止
2. 目的:为了避免请求发送者与多个请求处理者耦合在一起
```
```
角色:
1.抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接,如:代码中的Handler
2.具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者,如代码中的: StaffHandler,ManagerHandler,CEOHandler
3.Concrete Handler extends Handler
```
```
优缺点:
1. 降低了对象之间的耦合度,那个对象处理那个请求
2. 增强了系统的可扩展性,可以根据需要增加新的请求处理类,满足开闭原则
3. 责任链简化了对象之间的连接,每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句
缺点:
1. 若果链过于长了,会一定程度上影响系统的性能
2. 有可能到了链的末端,依然处理不了请求的,相当于一个请求到了末端的链没有得到一个结果,类似于做了无用功
```
### 命令: command
```
项目名: command
1. ?: 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作
2. 目的: 将请求封装成命令,然后执行该命令,
```
```
角色
1. 客户端角色(Client): 创建一个具体命令ConcreteCommand对象并确定其接收者
2. 接收者角色(Receiver): 负责具体实施和执行一个请求,任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法
3. 命令角色(Command): 声明一个给所有具体命令类的抽象接口
4. 具体命令角色(ConcreteCommand): 定义一个接收者和行为之间的弱耦合:实现execute()方法,负责调用接收者(Receiver)的相应操作.execute()方法通常叫做执行方法,即在方法中定义一个Receiver私有属性
5. 请求者角色(Invoker):负责调用命令(Command)对象执行请求,相关的方法叫做行动方法,即在方法中定义一个Command私有属性
```
```
优缺点:
优点:
1. 在一定程度上降低了耦合度,发起命令---客户端 和 接收命令的接收者对于客户端是完全解耦的,接收者对于客户端是不可见的
2.可以动态的控制,命令模式把请求封装起来,可以动态的对它进行参数化,队列化和日志化等操作,从而使得系统更灵活
缺点:
1. 当需要请求的命令越来越多的时候,具体命令类也越来越多
```
```
扩展: 的回调机制就是可以用命令模式实现
回调: 回调是一种双向的调用模式,也就是说,被调用的接口被调用时也会调用对方的接口,例如A要调用B,B在执行完又要调用A
```
```java
//回调接口
public interface CallBack {
/**
* 完成作业的接口 : 这是一个回调的接口
*/
void fishWork(String message);
}
```
```java
//相当于 A ---> A调用B 的doWork
public class Teacher implements CallBack{
private Student student;
public Teacher(Student student){
this.student = student;
}
@Override
public void fishWork(String message) {
System.out.println(message);
}
public void makeStudentDoWork(){
System.out.println("老师让"+student.getName()+"做作业");
student.doWork(this);
}
}
```
```java
//相当于 B --- B 回调了 A的fishWork()
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public void doWork(Teacher teacher){
//回调了 Teacher 的 fishWork() 方法 ----就是 学生做完了 然后给老师说我完了作业
System.out.println("开始做作业了");
System.out.println("做完了,我要给老师说我做完了");
teacher.fishWork(name+"已做完作业");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
```
```
过程: fishWork 是回调接口
Teacher 调用 Student.doWork , Student.doWork 调用了 Teacher.fishWork, 感觉 调了 一圈回到了自己,自己调用自己的感觉,这就是回调,
注意 Student 调用Teacher.fishWork 的Teacher调用 Student的是同一个 一定是 和 Teacher调用 Student的是同一个
```
### 解释器: interpreter
```
项目名:interpreter
1. ?:*给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
2. 目的: 对于一些固定文法构建一个解释句子的解释器
```
```
角色:
1. 抽象表达式角色(Expression): 声明一个所有的具体表达式角色都需要实现的抽象接口.这个接口主要是一个interpret()方法,称作解释操作
2. 终结符表达式角色(Terminal Expression): 实现了抽象表达式角色所要求的接口,主要是一个interpret()方法:文法中的每一个终结符都有一个具体终结表达式与之相对应.比如有一个简单的公式R=R1+R2,在里面的R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式
3. 非终结表达式角色(Nonterminal Expression): 文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式
4. 环境角色(Context): 这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200.这些信息都需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就够了
```
```
优缺点:
1.扩展性好.由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法.
2. 容易实现.在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易
缺点:
1. 使用场景少,只有在特定的场景下使用
2. 执行效率较低.解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦
3. 会引起类膨胀.解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护
```
### 迭代器: iterator
```
项目名:iterator
1. ?:*提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
2. 目的: 遍历元素
```
```
角色:
抽象迭代器(Iterator): 此抽象角色定义出遍历元素所需的接口
具体迭代器(ConcreteIterator): 此角色实现了Iterator接口,并保持迭代过程中的游标位置
抽象容器(Aggregate): 容器角色负责提供创建具体迭代器角色的接口,必然提供一个类似createIterator()这样的方法,在Java中一般是iterator()方法
具体容器(ConcreteAggregate): 实现容器接口定义的方法,创建出容纳迭代器的对象
```
```
优缺点:
优点:
1. 提供多种遍历方式,可以进行顺序,倒序遍历
缺点:
1.比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐
```
```
使用场景:
目前迭代器一般和容器挂钩,在java中Collection,List,Set,Map等已经实现了很多,目前我们基本上直接去使用
```
### 中介: mediator
```
项目名:mediator
1. ?:*用一个中介对象来封装一系列的对象交互.中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
2. 目的: 封装内部交互过程,从而使其耦合松散
```
```
角色
1. 抽象中介者(Mediator)角色: 定义出同事对象到中介者对象的接口,其中主要方法是一个(或多个)事件方法
2. 具体中介者(ConcreteMediator)角色: 实现了抽象中介者所声明的事件方法.具体中介者知晓所有的具体同事类,并负责具体的协调各同事对象的交互关系
3. 抽象同事类(Colleague)角色: 定义出中介者到同事对象的接口.同事对象只知道中介者而不知道其余的同事对象
4. 具体同事类(ConcreteColleague)角色: 所有的具体同事类均从抽象同事类继承而来.实现自己的业务,在需要与其他同事通信的时候,就与持有的中介者通信,中介者会负责与其他的同事交互
关系: 见图image目录下
```
```
优缺点:
优点:
1. 简化了对象之间的交互.
2. 将各同事解耦.
3. 减少子类生成.
4. 可以简化各同事类的设计和实现
缺点:
1.如果同事类过多的话,交互十分复杂,系统很难维护
```
```
使用场景:
qq聊天(多个用户交互)
```
### 备忘录: memento
```
项目名:memento
1. ?:*备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态
2. 目的: 通过一个备忘录类专门存储对象状态,将对象恢复到原先保存的状态
```
```
角色
1. Originator: 原发器.负责创建一个备忘录,用以记录当前对象的内部状态,通过也可以使用它来利用备忘录恢复内部状态.同时原发器还可以根据需要决定Memento存储Originator的那些内部状态
2. Memento: 备忘录.用于存储Originator的内部状态,并且可以防止Originator以外的对象访问Memento.在备忘录Memento中有两个接口,其中Caretaker只能看到备忘录中的窄接口,它只能将备忘录传递给其他对象.Originator可以看到宽接口,允许它访问返回到先前状态的所有数据.
3. Caretaker: 负责人.负责保存好备忘录,不能对备忘录的内容进行操作和访问,只能够将备忘录传递给其他对象.
关系: 见图image目录下
```
```
解释:
1.Originator原触发器 保存当前的 一个状态,同时记录状态的变化,记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据
2.Memento : 保存我们需要保存的那个时候的状态,责存储发起人对象的内部状态,在需要的时候提供发起人需要的内部状态.
3. Caretaker: 管理者角色,对备忘录进行管理,保存和提供备忘录.
=====================
Originator: 需要保存的状态的属性(如 state,或者游戏中的血量和蓝条),createMemento(创建当前状态的备忘录),restoreMemento(回滚到之前保存的状态)
Memento: 需要保存的状态的属性(如 state,或者游戏中的血量和蓝条)等
Caretaker: 保存和提供保存生成当前的备忘录 Memento, Memento 作为 Caretaker 的一个私有属性
```
```
优缺点:
优点
1. 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态
2. 实现了信息的封装,使得用户不需要关心状态的保存细节
缺点:
1. 消耗资源.如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存
使用场景:
ctrl + z,浏览器后退,游戏进度保存
注意: 这里代码是单备忘录,同时还有多备忘录
```
### 观察者/发布-订阅模式: observer ---是一种通知机制
```
项目名:observer
1. ?:*定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
2. 目的: 观察者模式(Observer)又称发布-订阅模式(Publish-Subscribe: Pub/Sub).它是一种通知机制,让发送通知的一方(被观察方)和接收通知的一方(观察者)能彼此分离,互不影响
```
```
角色:
1. Subject: 抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象.
2. ConcreteSubject: 具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知.
3. Observer: 抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己.
4. ConcreteObserver: 具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态
关系: 见图image目录下
```
```
优缺点
优点
1. 降低了目标与观察者直接的耦合关系
2. 目标和观察者是一种触发关系
3. 可以手动编写多种模式通信(广播,主题等)
4. 符合"开闭原则"
缺点
1. 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用
2. 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
```
```
场景:
Spring事件机制中,或者 消息队列
```
### 状态: state
```
项目名:state
1. ?:*允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类
2. 目的: 根据不同的状态,执行不同的操作
```
```
角色
Context: 环境类,定义客户感兴趣的接口,持有当前状态的具体状态的实例(拥有States属性),此外,他还定义了供外部调用者使用的状态模式的接口
State: 抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为
ConcreteState: 具体状态类,实现了State抽象接口,设置不同状态下的处理情况
关系: 见图image目录下
```
```
优缺点:
1. 封装了转换规则.
2. 枚举可能的状态,在枚举状态之前需要确定状态种类.
3. 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数
缺点:
1. 随着状态的增多,或者判断条件的增多,会使对象增多,代码越发复杂
2. 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
3. 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码
```
```
使用场景:
1. 行为随状态改变而改变的场景
2. 条件,分支语句的代替者
```
### 策略: strategy
```
项目名:strategy
1. ?:*定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化
2. 目的: 根据不同的需求场景,使用不同的策略进行计算,相互直接可以替换
3. 项目中有两种方式: 正常代码, 枚举
```
```
角色:
1. Context(环境类):环境类是使用算法的角色,向外部提供方法,它在解决某个问题(即实现某个方法)时可以采用不同的策略.拥有属性 Strategy,
2. Strategy(抽象策略接口类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口.环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法.
3. ConcreteStrategy(具体策略类):它实现了在抽象策略类(Strategy)中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理,不同的具体策略类描述不同的策略
关系: 见图image目录下
```
```
优缺点:
优点:
1. 结构清晰,把策略分离成一个单独的类--替换了传统的if else
2. 代码耦合度降低,安全性提高--各个策略的细节被屏蔽
缺点:
1. 每增加一个策略,就会增加一个策略类,当存在多个策略类的时候,系统就显得笨拙---当然是用枚举可以适当减少这种类的增长
2. 客户必须知道所有的测试,并自行决定使用哪一个策略类
使用场景:
Arrays.sort()
```
### 模板方法: templatemethod
```
项目名:templatemethod
1. ?:*定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
2. 目的: 定义一个操作的一系列步骤,对于某些暂时确定不下来的步骤,就留给子类去实现好了,这样不同的子类就可以定义出不同的步骤
3. 实现就是一个"继承"的关系实现
```
```
角色
1. 抽象父类模板(Abstract Template):
(1) 定义了一个或多个抽象操作,以便让子类实现.这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤.
(2) 定义并实现了一个模板方法.这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现.顶级逻辑也有可能调用一些具体方法父类中有一个调用其他方法的总方法
(3) 抽象父类可能会实现其中的一些步骤,但是剩下的步骤通过具体不同的功能交给不同功能的子类实现
2. 子类具体模板(Concrete Template):
(1) 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤
(2) 每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各
(3) 重写父类中"剩余步骤的方法",以实现不同的目标或者功能
关系: 见图image目录下
```
```
优缺点:
优点:
1. 提高代码复用性: 将相同的代码放到抽象类中
2. 提供了可扩展性: 将不同代码放入到不同的子类,通过对子类的扩展增加新的行为
1. 实现了反向控制: 通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为,实现了反向控制 & 符合“开闭原则”
缺点:
2. 引入了抽象类,每一个不同的实现都需要增加一个子类实现,导致类的个数增加,反而增加了系统实现的复杂度
应用场景:
1. 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复,
2. 子类的扩展
```
### 访问者: visitor
```
项目名:visitor
1. ?:*表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
2. 目的: 是一种操作一组对象的操作,它的目的是不改变对象的定义,但允许新增不同的访问者,来定义新的操作,新增不同的访问者增加不同的操作
```
```
角色:
1. 抽象访问者(Visitor)角色: 为该对象结构中具体元素角色声明一个访问操作接口
2. 具体访问者(ConcreteVisitor)角色:每个具体访问者都实现了Vistor中定义的操作
3. 抽象元素(Element)角色: 定义了一个accept操作,以Visitor作为参数
4. 具体元素(ConcreteElement)角色: 实现了Element中的accept()方法,调用Vistor的访问方法以便完成对一个元素的操作
5. 对象结构(Object Structure)角色:可以是组合模式(实现接口Element),也可以是集合(不实现接口Element),然后定义了Element集合属性,能够枚举它包含的元素,提供一个接口,允许Vistor访问它的元素
```
关系: 见图image目录下
//获取的是直接路径

```
优缺点:
优点:
1. 符合单一职责原则
2. 优秀的扩展性: 增加一个访问者,就可以增加不同的操作,灵活性高
缺点:
1. 实现特别复杂
2. 具体元素变更比较困难
3.
应用场景:
1. 访问者可以对功能进行统一,可以做报表,UI,拦截器与过滤器
```