设计模式

设计模式的7 大原则

  1. 开闭原则 对扩展开放,对修改关闭
  2. 里式替换原则 继承必须确保超类所拥有的性质在子类中仍然成立
  3. 依赖导致原则 上层模块不应该依赖底层模块,两者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象
  4. 单一职责原则 一个类应该右且仅有一个引起他变化的原因,否则类应该被拆分
  5. 接口隔离原则 一个类堆另外一个类的依赖应该建立在最小的接口上
  6. 迪米特法则 最少知道原则,无需字节交互的两个类,如果需要交互,使用中间者
  7. 合成复用原则 组合/聚合复用原则,软件复用时,要尽量使用组合或者聚合等关联关系来实现,其次才考虑集成关系实现

创建型模式

创建模式关注点 怎样创建出对象,将对象的创建和使用分离,

  1. 对应的创建由相关的工厂来完成 各种工程模式
  2. 对象的创建由一个建造者来完成 建造者模式
  3. 对象的床架由原来的对象克隆完成 原型模式
  4. 对象始终在系统中只有一个实例 单例模式

单例模式

一个单一的类,负责创建自己的对象,同时确保系统只有单个对象被创建

  1. 某个类只能右一个实例 构造器私有
  2. 他必须自行创建这个实例 自己遍历实例化逻辑
  3. 他必须自行想整个系统提供这个实例 对外整个系统提供实例化方法

原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。
本体给外部提供一个克隆体进行使用

  1. 资源优化
  2. 性能和安全要求
  3. 一个对象多个修改者的场景。
  4. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时可以考虑使用原型模式拷贝多个对象供调用者使用。
  5. 深(两个完全对象不一样的【递归克隆】,内容却完全一样)、浅(只是属性赋值)….
  6. 什么场景用到?
    资源优化
    性能和安全要求
    一个对象多个修改者的场景。
    一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时可以考虑使用原型模式拷贝多个对象供调用者使用。
    深(两个完全对象不一样的【递归克隆】,内容却完全一样)、浅(只是属性赋值)….
    ……

工厂模式

工厂模式(Factory Pattern)提供了一种创建对象的最佳方式。我们不必关心对象的创建细节,只需要根据不同情况获取不同产品即可。难点:写好我们的工厂

什么场景用到?
NumberFormat、SimpleDateFormat
LoggerFactory:
SqlSessionFactory:MyBatis
BeanFactory:Spring的BeanFactory(就是为了造出bean)

建造者模式

创建的东西细节复杂,还必须保留给使用者,屏蔽过程而不屏蔽细节。

什么场景用到?
StringBuilder:append(); 给谁append呢?
Swagger-ApiBuilder:
快速实现。Lombok-Builder模式

结构型模式

类结构型模式 关心类的组合,由多个类组合成一个更大的 继承

对象结构型模式 关心类和对象的组合,通过关联在一个类中定义另一个类的实例对象 组合

尽量使用关联关系来代替继承关系,

适配器模式

将一个接口转换成客户希望的另一个接口,适配器模式是接口不兼容的那些类可以一起工作,适配器模式分类接口模式和对象结构模式,

别名 Wrapper 包装器

主要角色

目标接口 Target

适配者类 Adaptee

适配器类 Adapter

什么场景用到?
Tomcat如何将Request流转为标准Request
Spring AOP中的AdvisorAdapter是什么
Spring MVC中经典的HandlerAdapter是什么
SpringBoot 中 WebMvcConfigurerAdapter为什么存在又取消
……

桥接模式

将抽象于实现解耦,使两者都可以独立变化

主要角色

  • 系统设计期间 如果这个类里边的一些东西,会扩展很多这个懂就应该分离出来

  • 抽象化角色,定义抽象类 并包含一个对实例化对象的引用

  • 扩展抽象化角色

  • 实现化角色
    什么场景用到?
    当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。
    当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
    当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。
    注意事项
    把一个大的类,抽象成几个小的抽象类,可以在抽象类中定义构造参数,然后继承的子类必须实现此构造
    在其中一个抽象类中组合另外几个抽象子类,组合调用。

装饰器模式

  • 向一个现有的对象添加新的功能,同时又不改变其结构。属于对象结构型模式。

  • 创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
    抽象构件(Component)角色:
    定义一个抽象接口以规范准备接收附加责任的对象。
    具体构件(ConcreteComponent)角色:
    实现抽象构件,通过装饰角色为其添加一些职责。
    抽象装饰(Decorator)角色:
    继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
    具体装饰(ConcreteDecorator)角色:
    实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
    什么场景使用?
    SpringSession中如何进行session与redis关联?HttpRequestWrapper
    MyBatisPlus提取了QueryWrapper,这是什么?
    Spring中的BeanWrapper是做什么?
    Spring Webflux中的 WebHandlerDecorator?

代理模式

代理模式(Proxy Pattern) ,给某一个对象提供一个代理,并由代理对象控制对原对象的引用,对象结构型模式。这种也是静态代理

什么场景用到?
MyBatis的mapper到底是什么?怎么生成的?
Seata的DataSourceProxy是什么?
DruidDataSource存在的Proxy模式

外观模式

外观(Facade)模式又叫作门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式

什么场景使用?
去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便。以此类比……
JAVA 的三层开发模式。
分布式系统的网关
Tomcat源码中的RequestFacade干什么的?

组合模式

把一组对象当成一个对象进行处理 例如属 树形菜单

享元模式

享元模式(Flyweight Pattern),运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。
在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。

有很多大量的重复使用的对象,维护一个享元池

享元模式包含如下角色:
Flyweight: 抽象享元类
ConcreteFlyweight: 具体享元类
UnsharedConcreteFlyweight: 非共享具体享元类
FlyweightFactory: 享元工厂类

行为型模式

模板方法(Template Method)模式:父类定义算法骨架,某些实现放在子类
策略(Strategy)模式:每种算法独立封装,根据不同情况使用不同算法策略
状态(State)模式:每种状态独立封装,不同状态内部封装了不同行为
命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开
职责链(Chain of Responsibility)模式:所有处理者封装为链式结构,依次调用
备忘录(Memento)模式:把核心信息抽取出来,可以进行保存
解释器(Interpreter)模式:定义语法解析规则
观察者(Observer)模式:维护多个观察者依赖,状态变化通知所有观察者
中介者(Mediator)模式:取消类/对象的直接调用关系,使用中介者维护
迭代器(Iterator)模式:定义集合数据的遍历规则
访问者(Visitor)模式:分离对象结构,与元素的执行算法

行为型模式关注点“怎样运行对象/类?”所以我们关注下类/对象的运行时流程控制
行为型模式用于描述程序在运行时复杂的流程控制,
描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。

模板方法模式

在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。

模板方法(Template Method)包含两个角色
抽象类/抽象模板(Abstract Class)
具体子类/具体实现(Concrete Class)

什么场景用到?
Spring的整个继承体系都基本用到模板方法
JdbcTemplate、RedisTemplate都允许我们再扩展…..
我们自己的系统也应该使用模板方法组织类结构
……

策略(Strategy)模式

策略(Strategy)模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。属于对象行为模式。

策略模式的主要角色如下。
抽象策略(Strategy)类:公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
环境(Context)类:持有一个策略类的引用,最终给客户端调用。

什么场景用到?
使用策略模式可以避免使用多重条件语句,如 if…else 语句、switch…case 语句
什么是Spring的 InstantiationStrategy
线程池拒绝策略

状态(State)模式

状态(State)模式:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

状态模式包含以下主要角色。
环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

什么场景用到?
策略模式和状态模式是一样的?状态模式更关注做什么,策略模式更关注怎么做
流程框架与状态机
……

中介者(Mediator)模式

中介者模式(Mediator Pattern):用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,减少对象间混乱的依赖关系,从而使其耦合松散,而且可以独立地改变它们之间的交互。对象行为型模式。

什么场景用到?
SpringMVC 的 DispatcherServlet是一个中介者,他会提取Controller、Model、View来进行调用。而无需controller直接调用view之类的渲染方法
分布式系统中的网关
迪米特法则的一个典型应用
…….

观察者(Observer)模式

观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。对象行为型模式

Subject: 目标
ConcreteSubject: 具体目标
Observer: 观察者
ConcreteObserver: 具体观察者

什么场景用到?
Spring事件机制如何实现?
Vue的双向绑定核心
响应式编程核心思想
……

备忘录(Memento)模式

备忘录(Memento)模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。对象行为型模式

发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

什么场景用到?
游戏存档
数据库保存点事务(savepoint)
session活化钝化
……

解释器(Interpreter)模式

解释器(Interpreter)模式:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。类行为型模式

抽象表达式(Abstract Expression)角色:
定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
终结符表达式(Terminal Expression)角色:
是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
非终结符表达式(Nonterminal Expression)角色:
也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
环境(Context)角色:
通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
客户端(Client):
主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。