design
南风未起 2022-04-08 20:38:22 Golang
# 1.设计模式分类
--- 创建型模式 单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式 --- 结构型模式 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式 --- 行为型模式 模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式1
2
3
4
5
6
# 2.单例模式
# 2.1.简介
采用一定方法保证整个软件系统中某个类只存在一个对象实例,并且该类只提供一个取得其对象实例的方法——例如SqlSessionFactory——Runtime饿汉式单例1
# 2.2.分类
--- 饿汉式 类内部创建对象,对外暴露获取方法 --- 懒汉式 - 线程不安全式——效率高,线程不安全 - 线程安全式——线程安全,效率低 - 加synchronized同步机制时不能加载new阶段,必须加在方法上——线程进入if判断后未执行,其他线程已new对象 --- 双重检查——推荐使用 保证线程安全同时尽量不影响效率 --- 静态内部类——推荐使用 - 外部装在时静态内部类不被装载 - 外部类调用getInstance时内部类才会被加载,并且只加载一次 - 采用类装载机制保证初始化实例时只有一个线程 - 类的静态属性只会在第一次加载类的时候初始化,JVM可以保证静态属性的线程安全 --- 枚举单例 - 避免多线程问题,防止反序列化重新创建对象 - java作者推荐使用的方式 --- 单例模式的应用场景 - 需要频繁创建、销毁的对象 - 创建时耗过多或耗费过多的重量级对象 - 工具类对象 - 频繁访问数据库或文件的对象——数据源、session工厂等1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 3.工厂模式
方法抽取到一个特定类中作为实例工厂,封装实例化对象的行为——Canlendar类。 --- 分类 - 简单工厂模式(静态工厂模式)——封装类的实例化 - 方法工厂模式——工厂抽象出方法,具体工厂继承者实现方法,对象的实例化推迟到子类 - 抽象工厂模式——工厂抽象方法,具体工厂继承者实现方法,此时的方法可水平扩展1
2
3
4
5
6
# 4.原型模式
# 4.1.克隆羊问题
# 4.1.1.传统方式
- 好理解,简单易操作 - 创建新对象时需要重新获取原始对象的属性,如果创建的对象比较复杂则效率较低 - 需要重新初始化对象,而不是动态获得对象的运行时状态,不够灵活1
2
3
# 4.1.2.改进
Java中的Object类是所有类的根类,提供了一个clone()方法,该方法可以将一个java对象复制一份。此时需要实现clone的java类必需实现Cloneable接口,该接口表示该类能够复制且有复制的能力——原型模式。1
# 4.2.内涵
- 用原型实例指定创建对象的种类,通过拷贝类型创建新的对象 - 创建型设计模式,允许一个对象创建另一个可定制的对象,无需直到创建细节 - 原理——通过将一个原型对象传给要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝他们自己来创建实例——xxx.clone()。1
2
3
# 4.3.浅拷贝
- 对于数据类型是基本类型的成员变量,浅拷贝会直接进行值传递,即将属性值复制一份给新的对象 - 对于数据类型是引用数据类型的成员变量,例如数组、某个类的对象,浅拷贝会进行引用传递,将成员变量的引用值(内存地址)复制一份给新的对象,即多个成员变量指向同一个地址。1
2
# 4.4.深拷贝
- 复制对象的所有基本数据类型成员变量的值 - 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象 - 实现方式——重写clone、序列化实现深拷贝 - 深拷贝方式 - clone克隆——基本数据克隆,类实例等成员变量单独克隆1
2
3
4
5
# 5.建造者模式
# 5.1.简介
又叫生成器模式,是一种对象构建模式,将复杂对象的建造过程抽取出来,使这个抽象过程的不同实现方式构造出不同的表现: 建造者模式一步步创建复杂对象,允许用户通过指定复杂对象的类型和内容即可构建。1
# 5.2.角色分类
- Product(产品角色)——具体的产品对象 - Builder(抽象建造者)——创建一个Product对象的各个部件指定的接口/抽象类 - ConcreteBuilder(具体建造者)——实现接口,构建和装配各个部件 - Director(指挥者)——构建一个使用Builder接口的对象——隔离客户与对象的生产过程,控制产品对象生产过程1
2
3
4
# 6.适配器模式
将某个类的接口转换为客户端期望的另一个接口表示,目的是兼容性,让原本因接口不匹配的两个类协调工作——遵循合成复用原则。 --- 适配器模式属于结构型模式——将原本不兼容的接口融合在一起工作 - 类适配器模式——实现被适配的类及要适配的接口——继承源类,实现目标接口 - 对象适配器模式——被适配的类以成员变量或方法参数形式出现,要实现的接口作为适配方的方法参数——持有源类的对象,把继承关系变为聚合关系 - 接口适配器模式——借由中间抽象类空实现目标接口所有方法,适配器选择性重写1
2
3
4
5
6
# 7.桥接模式
将实现与抽象放在不同类层,使两个层次可以独立变化,属于结构型设计模式——基于类的最小设计原则,通过封装、聚合、继承等让不同的类承担不同的职责,将抽象和行为的实现分离。1

jdbc的driver接口利用桥接模式——DriverManager——Connection1注意
- 抽象和实现分离,提高系统灵活性,有利于系统分层设计,使系统结构化
- 对于系统的高层部分,只需要直到抽象和实现的接口,具体细节由业务完成
- 替代多层继承方案,减少子类个数,降低系统管理和维护成本
- 增加了系统理解和设计难度,要求开发者针对抽象进行设计和编程
# 8.装饰者模式
动态将新功能附加到对象上,在对象功能扩展方面,比继承更有弹性,体现了开闭原则。 装饰者模式——基类被子类重新包装后返回基类或基类的子类实例,如下图m基类为饮料,其下为Coffee和Decorator子类,两者被子类包装。1
2
# 9.组合模式
又称部分整体模式,它创建了对象组的树形结构,将对象组合为树形结构用来表示整体—部分层次。组合模式使用户对单个对象和组合对象的访问具有一致性。 --- 核心 抽象基类定义属性及方法,子类实现某些方法,实现任意子类聚合。1
2
3
注意
- 简化客户端操作,客户端只需要面对一致对象而非考虑细节
- 扩展性强,更改组合对象时只需要调整内部层次关系
- 通过添加树枝节点或叶子节点获得复杂的层次结构
- 需要遍历层次结构时组合模式是个不错的选择
- 节点和叶子差异较大时不适合组合模式
# 10.外观模式
又称过程模式,为子系统的一组接口提供一致界面,即定义一个高层接口,屏蔽内部子系统细节,使子系统被统一使用。1
# 11.享元模式
又称蝇量模式,运用共享技术有效的支持大量细粒度对象。可以解决重复对象的内存浪费问题,最经典的应用场景为池技术——String常量池、数据库连接池等。1
- 共享Circle,如果map中没有对应颜色Circle则新建,否则共用 - Integer.valueOf()——享元模式1
2
注意
- 用唯一标识码判断是否有该对象,有则获取——HashMap存储
- 享元模式提高了系统的复杂度,需要分离内部状态和外部状态
# 12.代理模式
- 为对象提供一个替身,以控制这个对象的访问,即通过代理对象访问目标对象 - 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象 --- 静态代理 - ProxyImage代理RealImage,前者的diaplay调用后者的display - 优点——在不修改目标对象功能前提下,通过代理对象对目标功能扩展 - 缺点——代理对象需要与目标对象实现相同接口,产生很多代理类,且一旦接口增加方法,目标对象和代理对象都需要维护1
2
3
4
5
6
7
--- 动态代理 - 不需要实现接口,但是目标对象要实现接口,否则不能用动态代理 - 代理对象的生成,是利用JDK的API,动态在内存中构建代理对象 - 动态代理也叫做JDK代理、接口代理 - TeacherFactory代理Teacher,Teacher作为TeacherFactory成员变量,在构造时被实例化,并通过getProxyInstance方法获取其代理对象 - 通过Proxy.newProxyInstance实现invoke方法,获取代理类1
2
3
4
5
6
--- Cglib代理(可以在内存中动态创建对象而不需要实现接口) - 又称子类代理,在内存中构建一个子类对象从而实现对目标对象功能扩展,有时被归属为动态代理 - Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口,广泛的被许多AOP框架使用,实现方法拦截 - Cglib通过使用字节码处理框架ASM来转换字节码并生成新的类——代理对象实现MethodInteceptor接口 public class ProxyFactory implements MethodInterceptor { //维护目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } //返回一个代理对象 public Object getProxyInstance(){ //创建工具类 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(target.getClass()); //设置回调函数 enhancer.setCallback(this); //创建子类,即代理对象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Cglib代理模式开始……"); Object invoke = method.invoke(target, args); System.out.println("Cglib代理提交……"); return invoke; } } --- 代理模式的变体 - 防火墙代理——内网通过代理穿透防火墙,实现对公网的访问 - 缓存代理——获取资源时,先向缓存代理获取,获取不到时再到公网或数据库取,在进行缓存 - 远程代理——远程对象的本地代理,远程对象当做本地对象调用,远程代理通过网络真正和远程对象交互 - 同步代理——使用于多线程编程,完成多线程间同步工作1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 13.模板模式
- 在一个抽象类公开定义执行它的方法模板,其子类可以按需要重写方法实现,但调用将以抽象类中定义的方法执行 - 定义操作中的算法骨架,将步骤延迟到子类,使子类可以不改变算法结构重新定义实现步骤 - 行为型模式 - 钩子方法 - 不做任何事,子类可以视情况覆盖1
2
3
4
5
--- IOC容器初始化——refeshBeanFactory——模板模式 - getBeanFactory抽象方法 - refreshBeanFactory抽象方法 - postProcessBeanFactory后置处理器——钩子方法 - onrefresh钩子方法——模板方法refresh使用 --- 核心 - 算法只存在于父类,容易修改 - 实现代码最大复用 - 既实现统一的算法,也提供了最大灵活性 - 易导致类爆炸,新的实现需要扩展子类 - 一般模板方法会加final修饰,防止子类重写 - 常用于执行一系列相同步骤的流程1
2
3
4
5
6
7
8
9
10
11
12
13
# 14.命令模式
- 向某些对象发送请求,但并不知道请求者是谁,也不知道被请求的操作是哪个,而是在程序运行期间指定具体的请求接收者 - 命令模式使得请求接收者与发送者消除彼此之间的耦合,让对象之间的调用更加灵活 - 在命令模式中,会将一个请求封装为一个对象,以便使用不同参数表示不同请求,同时命令模式支持可撤销操作 - Invoker是调用者,Receiver是被调用者,MyComand是命令,实现Command接口或抽象类,持有接收对象 - 发起者持有命令对象——命令对象抽象命令实现者(接收者)——接收者执行真正命令 - 命令模式在Spring框架中的使用 - JdbcTemplate - 常用于订单撤销/恢复、撤销-反馈机制1
2
3
4
5
6
7
8
# 15.访问者模式
- 封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作,将数据结构和数据操作分离,解决数据结构和操作耦合性问题 - 访问者模式的基本工作原理是——在被访问的类里面加一个对外提供接待访问者的接口 - 应用场景——需要对一个对象结构中的对象进行很多不关联的不同操作,同时需比避免这些操作“污染”这些对象的类 - 双分派 - 不管类如何变化,总能找到期望的方法运行——双分派意味着得到执行的操作取决于请求的种类和接收者的类型 - 应用场景——系统有比较稳定的数据结构,又有经常变化的需求1
2
3
4
5
6
# 16.迭代器模式
行为型模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示——即不暴露内部结构。 - 优点 - 提供统一的方法遍历对象,客户不在考虑对象类型 - 隐藏了聚合的内部结构,客户端遍历聚合的时候只能读取到迭代器 - 提供一种设计思想,即一个类只有一个引起变化的原因(单一职责原则) - 缺点 - 每个举个对象都要一个迭代器,迭代器管理类众多 - 应用场景 - 展示一组相似对象,或者遍历一组相同对象时1
2
3
4
5
6
7
8
9
10
# 17.观察者模式
定义对象间的一种一对多的依赖关系,当一个对象状态发生改变时,所有依赖他的对象都得到通知并自动更新——在抽象类中有一个ArrayList存放观察者。 --- 优点 观察者与被观察者抽象耦合,它们之间建立了一种触发机制 --- 缺点 - 如果一个被观察者对象有很多直接和间接的观察者,通知到所有的观察者会话费更多时间 - 观察者和观察目标之间有循环依赖的话,观察目标会触发他们之间进行循环调用,导致系统崩溃 - 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅知道观察目标发生了变化 --- 使用场景 - 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这些方面封装在独立的对象中可以各自独立的改变和复用 - 一个对象的改变将导致其他的一个或多个对象也发生改变,而不知道具体有多少对象将发生变化,可以降低对象之间的耦合度 - 一个对象必须通知其他对象,而不知道这些对象是谁 - 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象 - Java内置中的观察者——Observe1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
注意
- Java中已经有了对观察者模式的支持类
- 避免循环引用
- 如果顺序执行,某一观察者错误会导致系统卡克一般采用异步方式
# 18.中介者模式
--- 简介 - 用一个中介对象封装一系列对象交互,中介者使各个对象不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互 - 中介者模式属于行为型模式,使代码易于维护 - MVC模式——C为中介者,在前后端交互时起到中间人作用 - 中介者保存的对象可用列表或hashMap收集保存 --- 优点 - 降低类的复杂度,将一对多转换为一对一 - 各个类之间解耦 - 符合迪米特原则 --- 缺点 - 中介者会庞大,变得复杂难以维护 --- 使用场景 - 系统中对象之间存在比较复杂的引用关系,导致依赖关系结构混乱而且难以复用该对象 - 想通过一个中间类封装多个类中的行为,而且又不想生成太多子类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 19.备忘录模式
--- 简介 - 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态 - 备忘录模式属于行为型模式 --- 实现 - Memento——包含被恢复对象状态的类 - Originator——创建并在Memento对象中存储状态 - Caretaker——负责从Memento中恢复对象状态 --- 优点 - 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史状态 - 实现了信息的封装,使得用户不需要关心状态的保存细节 - 缺点 - 消耗资源,如果类的成员变量过多,势必占用较大资源,而且每一次保存都会消耗一定的内存1
2
3
4
5
6
7
8
9
10
11
12
13
14
注意
- 为了符合迪米特原则,还需要增加一个管理备忘录的类
- 为了节约内存,可使用原型模式+备忘录模式
# 20.解释器模式
提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文,这种模式被用在SQL解析、符号处理引擎等。 --- 优点 - 可扩展性好,灵活 - 增加了新的解释表达式方式 - 易于实现简单文法 --- 缺点 - 可利用场景比较少 - 对于复杂的文法比较难维护 - 解释器模式会引起类膨胀 - 解释器模式采用递归调用的方法 - 使用场景 - 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树 - 一些重复出现的问题可以用一种简单的语言来进行表达 --- Java源码——SpeIExp——先创建parser——获取exoression对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
注意
- 可利用场景比较少,Java中如果碰到可以用expression4J 代替
# 21.状态模式
--- 简介 - 状态模式属于行为型模式 - 类的行为基于状态变化 - 在状态模式中,创建表示各种状态的对象和一个行为随着状态对象改变而改变的context对象 - 主要用来解决对象在多种状态转换 --- 优点 - 封装了转换规则 - 枚举可能的状态,在枚举状态之前需要确定状态种类 - 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新状态,只需要改变对象状态即可改变对象的行为 - 允许状态转换逻辑与状态对象合为一体,而不是某一个巨大的条件语句 - 可以让对个环境对象共享一个状态对象,从而实现对象复用 --- 缺点 - 状态模式的使用增加了系统类和对象的个数 - 状态模式的结构与实现较为复杂,如果使用不当将导致程序结构和代码混乱 - 状态模式对“开闭原则”支持不友好,对于可以切换状态的状态模式,增加新的状态类需要修改负责状态改变的源代码,否则无法切换到新增的状态,而且修改某个状态类的行为也需要修改对应的源代码 --- 使用场景 - 行为随状态改变而改变的场景 - 条件、分支语句的替代者——大量的if-else及switch语句可抽象为状态对象及行为的组合 - 例如借贷平台中的借贷状态变化1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
注意
- 在行为受状态约束的时候使用状态模式,状态最好不超过5个
# 22.策略模式
--- 简介 - 一个类的行为或其算法可以在运行时更改,在策略模式中创建表示各种策略的对象和一个行为随策略对象改变而改变的context对象,策略对象可以改变context对象的执行的算法。 - 策略模式属于行为型模式 - 思想——定义一系列的算法并进行封装,使其可相互替换 --- 优点 - 算法可以自由切换 - 避免使用多重条件判断 - 扩展性良好 --- 缺点 - 策略类会增多 - 所有策略类都需要对外暴露 --- 使用场景 - 如果在一个系统里有很多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态的让一个对象在多个行为间切换 - 一个系统需要动态地在几种算法中选择一种 - 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句实现 --- Java中策略模式的使用 - Arrays源码 - Comparator使用了策略模式 - 使用时需要实现Comparator接口——匿名类对象 new Comparator<>(){……} - new Comparator<>()就是实现了策略接口的对象,其策略通过实现接口内的compare方法指定1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
注意
- 如果一个系统的策略多于四个,则需考虑混合模式,解决策略模式类膨胀问题
- 核心思想——多用组合/聚合,少用集成
- 体现了“对修改关闭、对扩展开放的原则”
# 23.责任链模式
--- 简介 - 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求 - 为请求创建一个接收者对象的链,这种模式给予请求的类型,对请求的发送者和接收者进行解耦 - 责任链模式属于行为型模式 - 特点——责任链上的处理者负责处理请求,客户只需要将请求发送到责任链,无需关心请求处理细节和请求传递 - 核心——将请求处理方式按后置指针方式串联,依次遍历直至找到处理方法 --- 优点 - 降低耦合度,解耦请求的发送者与接收者 - 简化对象,使对象不需要知道链的结构 - 增强给对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态的新增或删除责任 - 增加新的请求处理类很方便 --- 缺点 - 不能保证请求一定被接收 - 系统性能将受到一定影响,在代码调试时不太方便,可能会造成循环调用 - 可能不容易观察运行时的特征,有碍于除错 --- 使用场景 - 有多个对象可以处理同一个请求,具体哪个对象处理请求由运行时刻自动确定 - 在不明确指定接收者情况下,向多个对象中的一个提交一个请求 - 可动态指定一组对象处理请求1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 24.过滤器模式
过滤器模式或标准模式是一种设计模式,这种模式允许开发人员使用不同的标准过滤一组对象,通过逻辑运算以解耦的方式将它们连接起来,这种类型的设计模式属于结构型模式。1
# 25.空对象模式
空对象取代NULL对象实例的检查,NULL不是检查空值,而是反映一个不做任何动作的关系。这样的null对象也可以在数据不可用的时候提供默认的行为。在空对象模式中,创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝的使用在需要检查空值的地方。1
# 26.MVC模式
--- Model-View-Controller(模型-视图-控制器)模式,该模式用于应用程序的分层开发 - Model(模型) 模型代表一个存取数据的对象或JAVA POJO,它也可以带有逻辑,在数据变化时更新控制器 - View(视图) 视图代表模型包含的数据的可视化。 - Controller(控制器) 控制器作用于模型和视图上,它控制数据流向模型对象,并在数据变化时更新视图,它使视图与模型分离开。1
2
3
4
# 27.数据访问对象模式
--- 又称为DAO模式,用于把低级的数据访问API或操作从高级业务服务中分离出来。 - 数据访问对象接口(Data Access Object Interface) 该接口定义了在一个模型对象上要执行的标准操作 - 数据访问对象实体类(Data Access Object concrete class) 该类实现了上述的接口,该类负责从数据源获取数据,数据源可以是数据库,也可以是xml,或者是其他的存储机制 - 模型对象/数值对象(Model Object/Value Object) 该对象是简单的 POJO,包含了get/set方法来存储通过使用DAO类检索到的数据1
2
3
4
# 28.拦截过滤器模式
用于对应用程序的请求或响应做一些预处理/后处理,定义过滤器并把请求传给实际目标应用程序之前应用在请求上。过滤器可以做认证、授权、记录日志,或者跟踪请求,然后把请求传给响应的处理程序。 --- 过滤器(Filter) 过滤器在请求处理程序执行请求之前或之后,执行某些任务 --- 过滤器链(Filter Chain) 过滤器链带有多个过滤器,并在Target上按照定义的顺序执行这些过滤器 --- Target Target对象是请求处理程序 --- 过滤管理器(Filter Manager) 过滤管理器管理过滤器和过滤器链 --- 客户端(Client) Client是向Target对象发送请求的对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16