【23种设计模式】23种设计模式简介及其应用 总纲

文章内容参考自:
设计模式大杂烩(24种设计模式的总结以及学习设计模式的几点建议)
部分设计模式及其应用

文章目录

  • 传送门
  • 什么是设计模式
  • 设计模式的好处
  • 1、单例模式
  • 2、工厂模式
    • 2.1、简单工厂模式
    • 2.2、工厂方法模式
  • 3、抽象工厂模式
  • 4、建造者模式
  • 5、原型模式
  • 6、代理模式
  • 7、适配器模式
  • 8、装饰者模式
  • 9、桥接模式
  • 10、享元模式
  • 11、组合模式
  • 12、外观模式
  • 13、观察者模式
  • 14、模板方法模式
  • 15、命令模式
  • 16、状态模式
  • 17、职责链模式
  • 18、解释器模式
  • 19、中介者模式
  • 20、访问者模式
  • 21、策略模式
  • 22、备忘录模式
  • 23、迭代器模式
  • 结束语

传送门

  • 设计模式七大原则、类之间的关系描述

创建型:单例模式 、工厂模式、 抽象工厂模式 、建造者模式 、原型模式

结构型: 代理模式、适配器模式、装饰器模式、桥接模式、组合模式、享元模式、外观模式

行为型:观察者模式、模板方法模式、命令模式、状态模式、职责链模式、解释器模式 、中介者模式、访问者模式、策略模式、备忘录模式、迭代器模式

什么是设计模式

  • 设计模式(Designpattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结
  • 设计模式是可以解决特定场景的问题的一系列方法
  • 反复使用:在很多的源码种都能体现出各种设计模式
  • 多数人知晓:也许前期开发你还没有意识到,但是随着系统的慢慢膨胀,就会意识到设计模式的重要性
  • 分类编目:设计模式可以根据一些特征去划分,分类
  • 代码设计经验:设计模式是设计经验的总结,也就是说设计模式是前人从他们自身众多的开发经验中总结出来的一系列模式,或者说是模板套路。

设计模式的好处

  • 设计模式可以帮助我们改善系统的设计,增强系统的健壮性、可扩展性
  • 在一个简单的开发中,也许你不会感受到设计模式所带来的好处,甚至还会觉得有一些复杂,但是随着系统慢慢的增加、修改,你会发现如果你不在乎设计模式,那么一旦你要增加一个小功能,你要改动的地方可能会非常的多,维护变得非常的艰难

1、单例模式

简介

  • 为什么要使用单例模式呢?
  • 单例模式顾名思义就是只有一个实例,换句话说就是无论你实例化多少个,其实都是一样的
  • 那么需要使用单例模式的类,应该是这些类,在应用中如果有两个或者两个以上的实例会引起错误,又或者这些类,在整个应用中,同一时刻,有且只能有一种状态
  • 那么我们使用单例模式,可以说是为了尽可能的节约内存空间,减少无谓的GC消耗,并且使应用可以正常运作
  • 举个例子:比如说配置信息,如果有多个,一旦需要修改一些配置,就可能会带来一些逻辑上的问题;又比如说一些工具类,如果有多个工具类,就会造成一定的性能浪费
  • 使用场景:应用中有对象需要是全局的且唯一
  • 选择使用的原因:一个对象在应用中出现多个实例是否会引起逻辑上或者是程序上的错误
  • 原型模式不同之处:单例模式是只有一个实例,原型模式每拷贝一次都会创造一个新的实例

源码应用

  • java.lang.Runtime
  • Spring依赖注入Bean实例默认是单例的

2、工厂模式

工厂模式分为:简单工厂模式 和 工厂方法模式

2.1、简单工厂模式

简介

  • 简单工厂模式定义:从设计模式的类型上来说,简单工厂模式属于创建型模式,又叫做静态工厂方法模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
  • 简而言之:就是由一个工厂对象决定创建出哪一种产品类的实例
  • 使用场景:需要在一堆产品中选择其中一个产品
  • 选择使用的原因:一种产品是否可根据某个参数决定它的种类
  • 工厂方法模式不同之处:工厂方法模式是简单工厂模式的进一步抽象化,在这两者之间做选择,主要看将工厂进一步抽象化是否有必要,通常情况下,如果工厂的作用仅仅是用来制造产品,则没必要使用工厂方法模式
  • 设计原则:遵循单一职责、违背开闭原则

源码应用

  • JDK8 中 Calendar 类获取日历类对象
  • JDBC 获取数据库连接 DriverManager类为工厂角色
  • Logback 中的 LoggerContextgetLogger() 方法获取 Logger 对象

2.2、工厂方法模式

简介

  • 工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,
  • 这样带来的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品
  • 使用场景:一种场景是希望工厂与产品的种类对客户端保持透明,给客户端提供一致的操作,另外一种是不同的工厂和产品可以提供客户端不同的服务或功能
  • 选择使用的原因:工厂类和产品类是否是同生同灭的关系
  • 抽象工厂模式不同之处:工厂方法模式与抽象工厂模式最大的区别在于,在工厂方法模式中,工厂创造的是一个产品,而在抽象工厂模式中,工厂创造的是一个产品族
  • 设计原则:遵循单一职责、依赖倒置、开闭原则

源码应用

  • Java集合接口 Collection 中的工厂方法模式
  • Logback中 ILoggerFactory 接口的 getLogger()方法

3、抽象工厂模式

简介

  • 定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类
  • 使用场景:需要一个接口可以提供一个产品族,且不必知道产品的具体种类
  • 选择使用的原因:产品族是否需要一起提供,且是否有一致的接口
  • 建造者模式不同之处:两者都是建造一批对象或者说产品,不同的是两者的目的和实现手段,在建造者模式中,是为了复用对象的构建过程而定义了一个指挥者,而在抽象工厂模式中,是为了提供一个这批对象的创建接口而定义了抽象工厂接口。
  • 设计原则:遵循单一职责、依赖倒置、开闭原则

源码应用

  • java.sql 包下的 Connection 接口

4、建造者模式

简介

  • 定义:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示
  • 使用场景:需要构建一批构建过程相同但表示不同的产品,而构建过程非常复杂
  • 选择使用的原因:各个产品的构建过程是否相同
  • 设计原则:遵循单一职责、开闭原则

源码应用

  • java.lang.StringBuilder 中的建造者模式
  • MyBatis 中的 SqlSessionFactoryBuilder

5、原型模式

简介

  • 定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
  • 使用场景:需要在运行时动态的创建指定实例种类的对象,或是需要复用其状态
  • 选择使用的原因:创建出来的对象是否可以立即投入使用
  • 关键点:使用原始模式的时候一定要注意为深克隆还是浅克隆

源码应用

  • Object 类中的 clone 接口
  • Spring中的Bean的创建(单例模式和原型模式)

6、代理模式

简介

  • 定义:为一个对象提供一个替身,以控制对这个对象的访问
  • 使用场景:需要修改或屏蔽某一个或若干个类的部分功能,复用另外一部分功能,可使用静态代理,若是需要拦截一批类中的某些方法,在方法的前后插入一些一致的操作,假设这些类有一致的接口,可使用JDK的动态代理,否则可使用cglib
  • 选择使用的原因
    • 静态代理:是否要复用被代理的部分功能
    • 动态代理:能否在将被代理的这一批类当中,找出相同的切入点
  • 设计原则:合成/复用原则
  • 适配器模式区别:对于适配器模式当中的定制适配器,它与静态代理有着相似的部分,二者都有复用功能的作用,不同的是,静态代理会修改一部分原有的功能,而适配器往往是全部复用,而且在复用的同时,适配器还会将复用的类适配一个接口

源码应用

  • Spring AOP

7、适配器模式

简介

  • 定义:将某个类的接口转换成客户端所期望的另一个接口表示出来,主要目的是兼容性,让原本因接口不匹配不能在一起工作的两个类可以协同工作
  • 使用场景:需要使用一个类的功能,但是该类的接口不符合使用场合要求的接口,可使用定制适配器,又或者是有一个接口定义的行为过多,则可以定义一个缺省适配器,让子类选择性的覆盖适配器的方法
  • 选择使用的原因:定制适配器的选择关键点在于是否有更加优良的替代方案,缺省适配器的选择关键点在于接口中的方法是否可以不全部提供,且都有缺省方案
  • 设计原则:遵循开闭原则、体现功能复用
  • 装饰者模式的区别:对于适配器模式中的定制适配器与装饰者模式,二者都是使用组合加继承的手段,不同的是,适配器模式的目的在于适配接口,装饰者模式的目的在于动态的添加功能,且可以叠加

源码应用

  • Spring AOP 中的 AdvisorAdapter
  • Spring JPA 中的 JpaVendorAdapter
  • Spring MVC 中的 HandlerAdapter

8、装饰者模式

简介

  • 定义:动态地给一个对象增加一些额外的职责
  • 使用场景:一个类需要动态的添加功能,且这些功能可以相互叠加
  • 选择使用的原因:添加的功能是否需要动态组装
  • 设计原则:遵循迪米特、单一职责、开闭原则,破坏里氏替换,体现功能复用

源码应用

  • Java I/O流
  • Spring session 中的 ServletRequestWrapper
  • Mybatis 中的 org.apache.ibatis.cache

9、桥接模式

简介

  • 定义:在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用桥接模式。而具体使用的方式,则是将抽象部分与他们的实现部分分离,使得它们都可以独立的变化。
  • 使用场景:一个对象有多个维度的变化,需要将这些维度抽离出来,让其独立变化
  • 选择使用的原因:是否可以将对象拆分成多个不相关的维度
  • 设计原则:遵循单一职责、迪米特、开闭原则,体现功能复用

源码应用

  • JDBC API

10、享元模式

简介

  • 定义:也称蝇量模式,运用共享技术有效的支持大量细粒度的对象,常用于池技术
  • 使用场景:一些状态相同的对象被大量的重复使用
  • 选择使用的原因:被共享的对象是否可以将外部状态提取出来

源码应用

  • Java中的String类、Integer类、Long类
  • Apache Commons Pool2

11、组合模式

简介

  • 定义:组合多个对象形成树形结构以表示具有 “整体—部分” 关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为 “整体—部分”(Part-Whole)模式,它是一种对象结构型模式。
  • 使用场景:当有一个结构可以组合成树形结构,且需要向客户端提供一致的操作接口,使得客户端操作忽略简单元素与复杂元素
  • 选择使用的原因:对外提供一致操作接口的结构是否可转化为树形结构
  • 设计原则:遵循依赖倒置、开闭原则,破坏接口隔离

源码应用

  • Java GUI中的 java.awt
  • Java的 HashMap
  • Mybatis 的 SqlNode

12、外观模式

简介

  • 定义:外观模式是软件工程中常用的一种软件设计模式。它为子系统中的一组接口提供一个统一的高层接口。这一接口使得子系统更加容易使用。
  • 使用场景:一个子系统需要对外提供服务
  • 选择使用的原因:子系统对外提供服务是否需要依赖很多的类
  • 设计原则:遵循迪米特
  • 中介者模式的区别:二者都是为了处理复杂的耦合关系,不同的是外观模式处理的是类之间复杂的依赖关系,中介者模式处理的是对象之间复杂的交互关系

源码应用

  • spring JDBC 中的org.springframework.jdbc.support.JdbcUtils
  • Mybatis中的org.apache.ibatis.session.Configuration
  • Tomcat 中的org.apache.catalina.connector.RequestFacade
  • SLF4J 没有替代任何日志框架,它仅仅是标准日志框架的外观模式

13、观察者模式

简介

  • 定义:观察者模式(有时又被称为发布-订阅模式、模型-视图模式、源-收听者模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被视作事件处理系统。
  • 使用场景:需要将观察者与被观察者解耦或者是观察者的种类不确定
  • 选择使用的原因:观察者与被观察者是否是多对一的关系
  • 设计原则:遵循迪米特、开闭原则

源码应用

  • JDK中的Observer
  • Spring ApplicationContext 事件机制

14、模板方法模式

简介

  • 定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式。
  • 使用场景:一批子类的功能有可提取的公共算法骨架
  • 选择使用的原因:算法骨架是否牢固
  • 设计原则破坏里氏替换,体现功能复用

源码应用

  • Java Servlet
  • Mybatis 中的 Executor接口

15、命令模式

简介

  • 定义:在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,我们可以将一组行为抽象为对象,实现“行为请求者”与“行为实现者”之间的松耦合。
  • 使用场景:行为的请求者与行为的处理者耦合度过高
  • 选择使用的原因:请求者是否不需要关心命令的执行只知道接受者
  • 设计原则:遵循迪米特、开闭原则
  • 职责链模式的区别:容易将二者关联在一起的原因是,二者都是为了处理请求或者命令而存在的,而且二者都是为了将请求者与响应者解耦,不同的是命令模式中,客户端需要知道一个命令的接受者,在创建命令的时候就把接受者与命令绑定在一起发送给调用者,而职责链模式中,客户端并不关心最终处理请求的对象是谁,客户端只是封装一个请求对象,随后交给职责链的头部而已,也正因为这样,二者的实现方式,有着很大的区别

源码应用

  • Spring 框架中的 JDBC Template
  • Struts中,在模型层都要继承一个Action接口,并实现execute方法,这个Action就是命令类

16、状态模式

简介

  • 定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
  • 使用场景:一个对象在多个状态下行为不同,且这些状态可互相转换
  • 选择使用的原因:这些状态是否经常在运行时需要在不同的动态之间相互转换
  • 设计原则:遵循单一职责、依赖倒置、开闭原则
  • 与策略模式的区别:二者的实现方式非常相似,策略接口与状态接口,具体的策略与具体的状态以及二者都拥有的上下文,如果看它们的类图,会发现几乎一模一样,而二者不同的地方就在于,状态模式经常会在处理请求的过程中更改上下文的状态,而策略模式只是按照不同的算法处理算法逻辑,而且从实际场景来讲,状态模式改变的是状态,策略模式改变的是策略

应用

  • 可以应用于一些项目审批流程,或者是借贷平台的订单审核(随着操作不同会改变订单的状态)

17、职责链模式

简介

  • 定义:又叫责任链模式,为了避免请求的发送者和接收者之间的耦合关系,使多个接受对象都有机会处理请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
  • 使用场景:一个请求的处理需要多个对象当中的一个或几个协作处理
  • 选择使用的原因:对于每一次请求是否每个处理的对象都需要一次处理机会
  • 设计原则:遵循迪米特

源码应用

  • Spring MVC 中的 HandlerExecutionChain 链中

18、解释器模式

简介

  • 定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
  • 使用场景:被频繁使用的语言是否可用文法表示
  • 选择使用的原因:有一种语言被频繁的使用
  • 设计原则:遵循单一职责

源码应用

  • Spring中的 SqlExpressionParser

19、中介者模式

简介

  • 定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
  • 使用场景:一个系列的对象交互关系十分复杂
  • 选择使用的原因:复杂的交互关系是否有共性可被中介者承担
  • 设计原则:遵循迪米特,破坏单一职责

源码应用

  • java.util.Timer
  • MVC模式中,Controller 是中介者,根据 View 层的请求来操作 Model 层
  • java.util.concurrent.Executor#executejava.util.concurrent.ExecutorService#submitTimer#schedule 类似

java.util系列源码解读之Timer定时器

20、访问者模式

简介

  • 定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
  • 使用场景:作用于一个数据结构之上的操作经常变化
  • 选择使用的原因:数据结构是否稳定以及操作是否经常变化
  • 设计原则:遵循倾斜的开闭原则

21、策略模式

简介

  • 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
  • 使用场景:算法或者策略需要经常替换
  • 选择使用的原因:客户端是否依赖于某一个或若干个具体的策略
  • 设计原则:遵循单一职责、依赖倒置、迪米特、开闭原则

源码应用

  • java.util.Comparator 接口
  • Spring Resource
  • Spring Bean 实例化

22、备忘录模式

简介

  • 定义:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
  • 使用场景:需要在对象的外部保存该对象的内部状态
  • 选择使用的原因:是否可以在必要的时候捕捉到对象的内部状态
  • 设计原则:遵循迪米特、开闭原则

23、迭代器模式

简介

  • 定义:提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示
  • 使用场景:需要迭代访问一个聚合对象中的各个元素,且不暴露该聚合对象内部的表示
  • 选择使用的原因:客户端是否关心遍历的次序
  • 设计原则:遵循迪米特
  • 访问者模式的区别:二者都是迭代的访问一个聚合对象中的各个元素,不同的是,访问者模式中,扩展开放的部分在作用于对象的操作上,而迭代器模式中,扩展开放的部分在聚合对象的种类上,而且二者的实现方式也有着很大的区别。

源码应用

  • java.util.ArrayList
  • MyBatis中的Cursor

结束语

  • 以上便是23种设计模式的各个特点与部分模式的对比,如果总结的过程当中有疏漏或是错误,请大家留言评论不吝赐教,一起进步!先对大家表示感谢了!
  • 设计模式属于内功那种类型,需要长时间的修炼学习,除此之外,学习设计模式也要看一点缘分和天赋的,也许你看了很久还是看不懂,也许你在某一刻突然就能顿悟了,这个真的是随缘
  • 对于学生来说(因为我还是个学生),也许会觉得设计模式有点大题小作,但是在做课设的时候真的会很加分,而且你在研究一些框架(Spring、MyBatis、SpringMVC)和JDK源码的时候,能让你更加理解他们的结构
  • 记得多回头看看这些设计模式,也许你每看一遍都能有一个全新的感悟
  • 设计模式会陪伴着你的开发路,设计模式都是很优秀的思想,但是记住,不要强行套模板,设计模式只是一种思想,要掌握其中的核心思想,能做到手到拈来,看似是却不是,这才是大师的境界。
  • 还有一个,多看开源的框架!

你可能感兴趣的:(23种设计模式)