花了30天才肝出来,史上最全面Java设计模式总结,看完再也不会忘 Posted 2021-12-03 Tom弹架构
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了花了30天才肝出来,史上最全面Java设计模式总结,看完再也不会忘相关的知识,希望对你有一定的参考价值。
Design Patterns: Elements of Reusable Object-Oriented Software(以下简称《设计模式》),一书由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides合著(Addison-Wesley,1995)。这四位作者常被称为“四人组(Gang of Four)”,而这本书也就被称为“四人组(或 GoF)”书。他们首次给我们总结出一套软件开发可以反复使用的经验,帮助我们提高代码的可重用性、系统的可维护性等,解决软件开发中的复杂问题。
设计模式已诞生20多年,其间相继出版的关于设计模式的经典著作不计其数。如果说GoF的《设计模式》是设计模式领域的“圣经”,那么之后出版的各种关于设计模式的书籍可称为“圣经”的“批注版”或者“白话版”。本书正是基于GoF的《设计模式》来编写的。
《设计模式》总结的是经验之谈,千万不要死记硬背,生搬硬套。下面来总体预览一下设计模式的分类和总结,如下表所示。
本文是我对“圣经”实践的精华总结,全文内容节选自《设计模式就该这样学》,这是一本可以真正能够落地的“设计模式”之书,也是目前唯一一本结合框架源码如何落地“设计模式”这个角度来理解设计模式的书。本文也将会结合JDK、Spring、MyBatis、Tomcat、Netty等经典框架源码展开对设计模式的分析。当然,本文还会结合我多年的“踩坑填坑”经验和“教学答疑”经验,用比“圣经”更深刻、更全面、更通俗、更生动、更有趣、更接地气的方式并且结合真实业务场景分析每种设计模式的优缺点,治愈“设计模式选择困难症”。选设计模式就像相亲选对象,一旦做好了接受TA缺点的准备,那TA就一定属于你。所以,本文对于日常开发而言更具有指导意义。
Tom弹架构,只弹干货不掺水,本文所有分享内容均从实战角度出发,不谈概念,只谈实战和应用落地
以下是根据本人的个人经验,对设计模式使用频率的总结,不可作为学术依据,仅供大家参考。因为设计模式的选择还是要依赖具体的业务场景的,每个人接触的业务领域都不一样,自然设计模式的选择也会不一样。
1.1 创建型设计模式
如下图所示,创建型设计模式中使用频率由高到低依次为工厂方法模式、抽象工厂模式、建造者模式、单例模式、原型模式。原型模式一般都有现成的工具类,自己造轮子的情况比较少。
1.2 结构型设计模式
如下图所示,结构型设计模式中使用频率由高到低依次为适配器模式、装饰器模式、代理模式、门面模式、组合模式、享元模式、桥接模式。其中桥接模式一般都有现成的工具类,自己造轮子的情况比较少。
1.3 行为型设计模式
如下图所示,行为型设计模式中使用频率由高到低依次为策略模式、观察者模式、责任链模式、解释器模式、模板方法模式、迭代器模式、中介者模式、命令模式、访问者模式、备忘录模式、状态模式。其中,观察者模式、解释器模式、迭代器模式、中介者模式、命令模式、访问者模式、备忘录模式一般都有现成的工具类,自己造轮子的情况比较少。
下面根据本人多年研究设计模式的经验总结,将压箱干货首次全网发布。如果本文对您有帮助一定要收藏,也欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注『 Tom弹架构 』可获取更多技术干货!
标题
备注
[Tom弹架构:为什么一定要学习设计模式]()
2021/10/29已更新
目录仅代表更新计划,因精力分配原因不一定按顺序目录顺序连载,计划1个月(即2021年11月31日前)连载完毕,请小伙伴们持续关注本文更新,大家可以先关注和收藏本文或者关注『 Tom弹架构 』更新通知,感谢您的支持!
各种设计模式对比及编程思想总结如下表所示。
不管是面试也好,还是日常开发也好,相信大家都已经胸有成竹、信心满满了。但是从笔者的架构经验和教学经验总结来看,还有很多小伙伴对一些设计模式经常混淆难懂。以下内容将是我对设计模式的最精华总结,收集了我在教学过程中很多来自学员的疑问,对各种容易混淆的设计模式进行比较,并总结整理了以下内容,希望帮助大家在以后的设计选型中能够披荆斩棘,如履平地。如果你在阅读本书之前,对设计模式较为熟悉,本章内容可以帮助你巩固加深理解。
9.1 工厂方法模式与抽象工厂模式对比
对比
说明
共同点
1. 都属于创建型设计模式。<br> 2. 职责相同
不同点
所创建产品的扩展程度不同:工厂方法模式只能单向维度扩展产品;而抽象工厂模式可以让产品等级结构和产品族的相互扩展,而且可以多维度扩展(至少是二维扩展)
关联性
抽象工厂很多时候不一定是接口,而是抽象类;工厂方法类一般作为抽象工厂类的子类
类图对比
类图解释
从类图上看,抽象工厂模式中的抽象产品可以是多个维度的,而工厂方法模式中的抽象产品是单维度的。因此抽象工厂模式中的产品可以支持多维度扩展,而工厂方法模式中的产品只能单维度扩展。一个抽象工厂可以创建同一产品族下的多个抽象产品,而工厂方法模式并没有引入产品族的概念,只要是抽象产品的实现类都可以创建
9.2 简单工厂模式与单例模式对比
对比
说明
共同点
1.都属于创建型设计模式。<br>2.都会提供对外的获取对象的方法
不同点
职责不同:单例模式的职责是确保一个类在Java虚拟机里只有一个对象,整个系统共享这个对象;简单工厂模式的职责是封装对象的创建细节
关联性
在实际业务代码中,通常把工厂类设计为单例对象
类图对比
类图解释
从类图上看,单例模式和简单工厂模式并没有直接的关联
9.3 简单工厂模式与建造者模式对比
对比
说明
共同点
1. 都属于创建型设计模式。 <br>2. 职责相同,都是将创建产品的细节封装起来
不同点
1. 目的不同:简单工厂模式关注创建一个完整的标准产品,而建造者模式更关注创建个性化的产品。<br>2. 产品的复杂度不同:简单工厂模式创建的一般都是单一性质的产品,建造者模式可以创建复合型产品。一般来说,简单工厂模式创建的产品对象粒度比较粗,建造者模式创建的产品对象粒度更细
关联性
在实际业务代码中,通常把工厂类设计为单例对象
类图对比
类图解释
从类图上看,建造者模式比简单工厂模式多了一个建造者类。对于客户端而言,用户在调用build()方法之前都只是对产品参数的预设。而在简单工厂模式中,没有预设参数的动作,直接调用创建产品的方法获取产品的实例
10.1 装饰器模式与代理模式对比
对比
说明
共同点
1. 都属于结构型设计模式。<br>2. 都是包装器模式的实现。<br>3. 都是为了达到功能增强的目的
不同点
1. 实现形式不同:代理模式通过组合实现功能增强和扩展,装饰器模式通过继承实现增强和扩展。<br>2. 目的不同:代理模式着重代理的过程控制,而装饰器模式则是对类功能的加强或减弱,更注重类功能的变化。<br>3. 可扩展程度不同:装饰器模式的代码扩展灵活度更大,代理模式的扩展相对来说依赖性更强
关联性
装饰器模式可以说是静态代理模式的一个特殊应用
类图对比
类图解释
从类图上看,装饰器模式中会设计一个抽象的组件,后面不管是装饰器还是具体的组件,都是抽象组件的实现类,属于同一继承体系,功能扩展是在具体的装饰器中完成的。而代理模式用的是硬编码,功能的扩展简单粗暴
10.2 装饰器模式与门面模式对比
对比
说明
共同点
1.都属于创建型设计模式。<br>2.都是包装器模式的实现
不同点
目的不同:装饰器模式的主要目的是统一多个子系统的访问入口,承担一定的静态代理作用,大部分时候也会用到委派模式。装饰器模式的主要目的是功能扩展,而且扩展的类与目标类一定是同宗同源的
关联性
从代码结构上看,二者都是包装器模式的一种实现,二者也都会用到静态代理
类图对比
类图解释
从类图上看,门面模式中的门面类更像是一个万能的类,看上去涵盖了所有子系统的功能。而装饰器模式更符合单一职责原则
10.3 装饰器模式与适配器模式对比
对比
说明
共同点
1. 都属于结构型设计模式。<br>2. 都是包装器模式的实现
不同点
1. 代码结构不同:装饰器模式包装的都是自己的兄弟类,同宗同源;而适配器模式则是将一个非本家族的对象伪装起来。<br>2. 设计目的不同:适配器模式的意义是将一个接口转变成另一个接口,通过改变接口来达到重复使用的目的;而装饰器模式不是要改变被装饰对象的接口,而是恰恰要保持原有的接口,但是增强原有对象的功能,或者改变原有对象的处理方式,从而提升性能
关联性
装饰器模式和适配器模式只有结构上容易混淆,在具体业务场景中还是很容易区分的
类图对比
类图解释
从类图上看,没有太多的相似点。装饰器模式多了一个抽象装饰者,便于子类扩展。而适配器模式没有抽象装饰者这一层,直接扩展接口
10.4 适配器模式与代理模式对比
对比
说明
共同点
1. 都属于结构型设计模式。<br>2. 都是包装器模式的实现。<br>3. 二者都起到了隐藏和保护原类的作用
不同点
目的不同:适配器模式主要解决兼容问题,会保留被适配对象已经存在的方法并继续对外开放调用;而代理模式主要是为了功能增强,目标类的方法不会直接提供给用户调用,而是调用代理类的方法获得增强后的结果
关联性
对象适配器就是静态代理的一种实现
类图对比
类图解释
从类图来看,代理模式中的目标类和代理类继承同一父类,而适配器模式中只有适配器类才继承目标接口
11.1 策略模式与模板方法模式对比
对比
说明
共同点
1. 都属于行为型设计模式。<br>2. 都可以用来分离高层的算法和低层的具体实现细节,允许高层的算法独立于它的具体实现细节重用
不同点
1. 开放程度不同:策略模式允许外界调用其接口方法,而模板方法模式则限制接口方法只能在子类调用。<br>2. 方法控制权不同:模板方法模式采用继承的方式实现算法的异构,其关键点就是将算法封装在抽象基类中,并将不同的算法实现细节放在子类中实现,控制权在用户。而模板方法模式符合依赖倒置原则,父类调用子类的操作,底层模块实现高层模块声明的接口。这样控制权在父类,底层模块要依赖高层模块
关联性
有时候会混合使用,模板方法模式中可能设计的钩子方法,就是某一个策略的实现
类图对比
类图解释
从类图来看,在策略模式中的策略类,是实现策略抽象接口的全部方法。而在模板方法模式中,具体的实现类只实现模板类的部分方法,模板类通常为抽象类,而非接口
11.2 策略模式与命令模式对比
对比
说明
共同点
1. 都属于行为型设计模式。<br>2. 都需要对外提供一个功能清单给用户选择
不同点
业务场景不同:当不使用命令模式时,请求和处理的代码是写在一起的,但通常会降低调用者的体验,因此命令模式通常用于解耦请求和处理的场景。使用命令模式一般会有一个回调,反馈和处理结果。而策略模式则是封装算法,提供固定好的选项,让用户参与到业务的执行过程中,选择不同的策略最终会得到同一类型的结果。因为每一种策略都是可以相互替换的
关联性
命令模式内部的有些逻辑处理可以设计成策略模式
类图对比
类图解释
从类图来看,一个命令在形式上很像一种策略。只是命令模式多了一个接收者角色。但是在命令模式中,每条命令都是不能相互替换的,而在策略模式中,每种策略都是可以相互替换的
11.3 策略模式与委派模式对比
对比
说明
共同点
都属于行为型设计模式
不同点
关注点不同:策略模式关注策略是否能相互替代,而委派模式更关注分发和调度的过程
关联性
委派模式内部通常会用到策略切换的上下文容器
类图对比
类图解释
从类图上看,策略模式中上下文容器只是算法策略的选择切换所在,不需要实现策略接口。委派模式中委派者和被委派者实现了同一个接口
11.4 桥接模式与适配器模式对比
对比
说明
共同点
1. 都属于行为型设计模式。<br>2. 代码组织结构类似:适配器模式和桥接模式都是间接引用对象,因此可以使系统更灵活,在实现上都涉及从自身以外的一个接口向被引用的对象发出请求
不同点
1. 适用场景不同:适配器模式主要解决已有接口间的兼容问题,被适配的接口实现像是一个黑匣子,我们不想也不能修改这个接口及其实现,也不可能控制其演化,只要相关的对象能与系统定义的接口协同工作即可。适配器模式经常被用在与第三方产品的功能集成上,采用适配器模式适应新类型的增加的方式是开发针对这个类型的适配器。桥接模式则不同,参与桥接的接口是稳定的,用户可以扩展和修改桥接中的类,但是不能改变接口。<br>2. 设计原则不同:桥接模式不使用继承建立联系。而适配器模式中类适配器写法用的继承,对象适配器写法用的组合,接口适配器写法实际上用的也是继承,与桥接模式有由根本区别
关联性
按照GoF的说法,桥接模式和适配器模式用于设计的不同阶段,桥接模式用于设计的前期,即在设计类时将类规划为逻辑和实现两个大类,是它们可以分别精心演化的;而适配器模式用于设计完成之后,当发现设计完成的类无法协同工作时,可以采用适配器模式。然而很多情况下在设计初期就要考虑适配器模式的使用,如涉及大量第三方应用接口的情况
类图对比
类图解释
从类图上看,桥接模式比适配器模式更复杂,实际上多了一个桥接角色
11.5 桥接模式与组合模式对比
对比
说明
共同点
都属于行为型设计模式
不同点
目的不同:桥接模式的目的是将两个继承体系建立连接,是为了满足个性的需求的。而组合模式的目的不是建立连接,而是统一行动,统一成同一套API便于整体操作
关联性
桥接模式和组合模式关联性不大
类图对比
类图解释
从类图上看,桥接模式相对组合模式而言,其类图要复杂得多。桥接模式中抽象和实现不使用继承。而在组合模式中,所有的节点都具有共同的抽象,只有这样才能够统一操作
12.1 享元模式与容器式单例模式对比
对比
说明
共同点
1. 都设计了一个缓存对象的容器。<br>2. 设计目的有相似之处,两者都是为了节省内存开销
不同点
1. 类型不同:享元模式属于结构型设计模式,容器式单例模式属于创建型设计模式。<br>2. 对创建对象的控制粒度不同:享元模式可以再次创建对象,也可以取缓存对象。而单例模式则严格控制应用程序中只有一个实例对象。<br>3. 实现形式不同:享元模式可以通过自己实现对外部的单例,也可以在需要的时候创建更多的对象;单例模式是自身控制,需要增加不属于该对象本身的逻辑
关联性
享元模式可以看成是单例模式的扩展,可以把对象池的容器设置为单例。同时,把对象池所在的类设置为单例的工厂。 <br>享元模式 = 单例模式 + 工厂模式 + 组合模式
类图对比
类图解释
从类图上看,享元模式的类图比单例模式要复杂,但是都提供了一个获取对象的方法
12.2 建造者模式与装饰器模式对比
对比
说明
共同点
都有扩展装饰的作用
不同点
1.类型不同:建造者模式属于创建型设计模式,装饰器模式属于结构型设计模式。<br>2.应用场景不同:建造者模式针对构建复杂对象,且构建过程不稳定,强调对象创建步骤的个性化,一般来说会有标配;而装饰器模式针对建造过程十分稳定的情况,采用大桶套小桶
关联性
二者很少会出现混合使用的情况
类图对比
类图解释
从类图上看,并没有太多的相似点
12.3 策略模式与简单工厂模式对比
对比
说明
共同点
客户端调用方式相同:两者都是通过传入参数进行配置的。
不同点
1.类型不同:策略模式属于行为型设计模式,简单工厂模式属于创建型设计模式。<br>2.侧重点不同:简单工厂模式则是通过传参选择创建出需要的对象,而策略模式则是通过传参配置出需要的行为算法。一个是对象创建,另一个是行为算法的替换。<br>3.设计逻辑不同:两者的差别很微妙,简单工厂模式是直接创建具体的对象并用该对象去执行相应的动作。而策略模式设计一个上下文(Context)类,将操作给了上下文类,策略类内部没有创建具体的对象,从而实现代码的进一步封装,客户端代码并不需要知道具体的实现过程
关联性
一般来说,二者会组合使用,具体策略将由工厂来创建
类图对比
类图解释
从类图上看,策略模式和简单工厂模式非常相似,都通过多态来实现不同子类的选取,这种思想应该是从程序的整体看出来的
12.4 策略模式与适配器模式对比
对比
说明
共同点
都是通过找到已经存在的、运行良好的类来实现接口的
不同点
1. 类型不同:策略模式属于行为型设计模式,适配器模式属于结构型设计模式。<br>2. 目的不同:策略模式把一系列算法封装起来,提供一个统一的接口给客户,并使这些算法可以相互间替换;而适配器模式将一个类的接口转换成客户希望的另外一个接口,从而使原本因接口不兼容不能一起工作的类可以一起工作。<br>3. 客户单端调用方式不同:策略模式的所有策略都需要暴露出去,由客户端决定使用哪一种策略。而适配器模式是定义好接口的实现方式及内部需要引用的类,客户端直接调用适配器的方法
关联性
策略模式很多时候都和适配器模式结合使用,把具体适配器作为具体策略,用户选择不同策略从而调用不同的适配器方法
类图对比
类图解释
从类图上看,策略模式中方法的形参为接口对象,实参为接口的实现类。而适配器模式中在适配器中定义适配者来辅助实现接口
12.5 中介者模式与适配器模式对比
对比
说明
共同点
二者本质上都是一样的,在一个类中调用另一个类中的方法,从而减少耦合
不同点
1.类型不同:中介者模式属于行为型设计模式,适配器模式属于结构型设计模式。<br>2.目的不同:中介者模式主要完成资源协调,而适配器模式主要解决兼容问题。<br>3.代码结构不同:中介者模式一定是用组合的形式实现代码复用的,所有人可能都持有中介者的引用:而适配器模式可以用继承的方式实现,也可以用组合的方式来实现代码复用
关联性
二者并没有明显的关联性
类图对比
类图解释
从类图上看,适配器采用的是对象适配器的类图,适配者和被适配者是组合复用的关系。中介者模式中具体的同事类都是持有中介者的引用。适配者和中介者都实现了一个接口(抽象)
12.6 中介者模式与代理模式对比
对比
说明
共同点
都具备保护目标对象的特性
不同点
1. 类型不同:中介者模式属于行为型设计模式,代理模式属于结构型设计模式。<br>2. 干预程度不同:如果说代理模式是“媒婆”,那么中介者模式就是“不负责任的媒婆”。<br>3. 职责不同:代理模式的职责是功能增强,不仅要将目标对象和代理对象建立联系,代理对象还要参与过程。而中介者模式中的中介者只负责牵线搭桥,建立联系,不参与具体的过程
关联性
中介者模式是一种面向更加复杂的对象关系的全权静态代理(委托)
类图对比
类图解释
从类图上看,Proxy类和Mediator都具备中介的功能,可以达到保护目标类的作用
12.7 中介者模式与桥接模式对比
对比
说明
共同点
都具备将两个对象建立联系的特性
不同点
1.类型不同:中介者模式属于行为型设计模式,桥接模式属于结构型设计模式。<br>2.适用场景不同:桥接模式只适用于将两个维度建立连接;而中介者模式可以将多个维度建立连接
关联性
中介者模式是一种更为复杂的桥接模式,中介者可以和网状结构的对象建立连接,而桥接模式只能和两个维度的对象建立连接
类图对比
类图解释
从类图上看,中介者模式和桥接模式还是非常相似的,只是中介者模式中采用的是组合复用,而桥接模式中采用的是继承复用。可以说中介者模式是桥接模式的升级版
12.8 桥接模式与命令模式对比
对比
说明
共同点
都是为了达到解耦的目的
不同点
1.类型不同:桥接模式属于结构型设计模式,命令模式属于行为型设计模式。<br>2.目的不同:桥接模式需要一个中间的实现类,以达到抽象和具体之间解耦的目的。而命令模式需要一个抽象的中间类,只是为了规范,达到请求和处理解耦的目的
关联性
桥接模式和命令模式组合使用的场景不常见
类图对比
类图解释
从类图上看,桥接模式通过抽象角色来与抽象维度和具体维度建立连接,而命令模式通过封装命令对象,将调用者角色和接收者角色建立连接,二者分别适用于不同的业务场景
12.9 委派模式与门面模式对比
对比
说明
共同点
从代码结构上看,都是包装器模式,也是一种静态代理,都具有包装对象的特性
不同点
1.类型不同:委派模式属于行为型设计模式,门面模式属于结构型设计模式。<br>2.侧重点不同:委派模式针对行为上的统一调度和分发,而门面模式是针对组织结构上的统一入口
关联性
在门面模式中,可能会用到委派模式实现任务分发
类图对比
类图解释
从类图上看,委派模式和门面模式非常相似,只是在委派模式中多了一个接口,而门面模式没有一个公共的接口
12.10 委派模式与代理模式对比
对比
说明
共同点
都有保护目标对象的特性
不同点
1.类型不同:委派模式属于行为型设计模式,代理模式属于结构型设计模式。<br>2.职责不同:委派模式虽然结构上是一种全权的静态代理,但对目标类的功能不做任何的增强;而代理模式中的代理类一定会对目标类进行功能增强
关联性
委派模式就是全权的静态代理,不做任何的代码增强
类图对比
类图解释
从类图上看,委派模式和代理模式几乎一致。只是委派模式是一个类代理多个目标类,而代理模式是一个类只代理一个目标类
在《设计模式就该这样学》一书中,还有大量的UML图及易混淆的设计模式对比案例分析,也欢迎大家关注。
在日常应用中,设计模式从来都不是单个设计模式独立使用的。在实际应用中,通常多个设计模式混合使用,你中有我,我中有你。下图完整地描述了设计模式之间的混用关系,希望对大家有所帮助。
大家可以先关注和收藏本文,感谢您的支持! 关注微信公众号『 Tom弹架构 』回复“设计模式”可获取完整源码。
以上是关于花了30天才肝出来,史上最全面Java设计模式总结,看完再也不会忘的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# 爆肝30天,肝出来史上最透彻Spring原理和27道高频面试题总结
11.29-12.5博客精彩回顾
史上最全的JAVA面试总结
史上最全!Java最新实习面试经验总结,分享面经
最强福利!史上最全的JAVA面试题
神级程序员花了20天整理出最全面的正则表达式干货!史上最全资料