设计模式
2020-09-10 13:42:56 0 举报
AI智能生成
总结了常用的设计模式特点及应用场景
作者其他创作
大纲/内容
创建型
单例模式
一个类只允许创建一个对象(或者实例)
意义
处理资源访问冲突
表示全局唯一类
实现
饿汉式
饿汉式的实现方式,在类加载的期间,就已经将 instance 静态实例初始化好了,所以,instance 实例的创建是线程安全的。不过,这样的实现方式不支持延迟加载实例。
懒汉式
懒汉式相对于饿汉式的优势是支持延迟加载。这种实现方式会导致频繁加锁、释放锁,以及并发度低等问题,频繁的调用会产生性能瓶颈。
双重检测
双重检测实现方式既支持延迟加载、又支持高并发的单例实现方式。只要 instance 被创建之后,再调用 getInstance() 函数都不会进入到加锁逻辑中。所以,这种实现方式解决了懒汉式并发度低的问题。
静态内部类
利用 Java 的静态内部类来实现单例。这种实现方式,既支持延迟加载,也支持高并发,实现起来也比双重检测简单。
存在的问题
单例对 OOP 特性的支持不友好
单例会隐藏类之间的依赖关系
单例对代码的扩展性不友好
单例对代码的可测试性不友好
单例不支持有参数的构造函数
工厂模式
当创建逻辑比较复杂,是一个“大工程”的时候,我们就考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离
实现
简单工厂
工厂方法
抽象工厂
建造者模式(Builder 模式)
如果一个类中有很多属性,为了避免构造函数的参数列表过长,影响代码的可读性和易用性,考虑使用建造者模式
实现
与工厂模式区别
工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象
建造者模式是用来创建一种类型的复杂对象,可以通过设置不同的可选参数,“定制化”地创建不同的对象
原型模式
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的
实现方式
浅拷贝
浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象
深拷贝
深拷贝得到的是一份完完全全独立的对象。所以,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间。
结构型
代理模式
在不改变原始类(或叫被代理类)的情况下,通过引入代理类来给原始类附加功能
应用场景
代理模式常用在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志
附加功能与业务功能解耦,放到代理类统一处理,让程序员只需要关注业务方面的开发
实现方式
静态代理
基于组合
我们让代理类和原始类实现同样的接口
优点在于更加灵活,对于接口的所有子类都可以代理,缺点在于不需要扩展的方法也需要进行代理
基于继承
如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式。
优点在于只需要针对需要扩展的方法进行代理,缺点在于只能针对单一父类进行代理
问题:静态代理需要针对每个类都创建一个代理类,并且每个代理类中的代码都有点像模板式的“重复”代码,增加了维护成本和开发成本
动态代理
我们不事先为每个原始类编写代理类,而是在运行的时候动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类
桥接模式
一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展
装饰器模式
装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承
装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类
装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点
适配器模式
这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作
实现方式
类适配器
类适配器使用继承关系来实现
对象适配器
对象适配器使用组合关系来实现
应用场景
封装有缺陷的接口设计
统一多个类的接口设计
替换依赖的外部系统
兼容老版本接口
适配不同格式的数据
门面模式
门面模式,也叫外观模式;为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。
应用场景
解决易用性问题
解决性能问题
组合模式
将一组对象组织(Compose)成树形结构,以表示一种“部分 - 整体”的层次结构
组合模式,将一组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现
使用组合模式的前提在于,你的业务场景必须能够表示成树形结构。所以,组合模式的应用场景也比较局限,它并不是一种很常用的设计模式
享元模式
所谓“享元”,顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象
当一个系统中存在大量重复对象的时候,我们就可以利用享元模式,将对象设计成享元,在内存中只保留一份实例,供多处代码引用,这样可以减少内存中对象的数量,以起到节省内存的目的
享元模式的代码实现非常简单,主要是通过工厂模式,在工厂类中,通过一个 Map 或者 List 来缓存已经创建好的享元对象,以达到复用的目的
在单例模式中,一个类只能创建一个对象,而在享元模式中,一个类可以创建多个对象,每个对象被多处代码引用共享
行为型
观察者模式
在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知
实现方式
同步阻塞的实现方式
异步非阻塞的实现方式
进程内的实现方式
跨进程的实现方式
模板模式
模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现
模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤
模板模式有两大作用:复用和扩展
策略模式
定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端
最常见的应用场景是,利用它来避免冗长的 if-else 或 switch 分支判断
它解耦的是策略的定义、创建、使用这三部分
策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类
策略的创建由工厂类来完成,封装策略创建的细节
客户端代码如何选择使用哪个策略,有两种确定方法:编译时静态确定和运行时动态确定
职责链模式
将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止
职责链模式有两种常用的实现。一种是使用链表来存储处理器,另一种是使用数组来存储处理器,后面一种实现方式更加简单。
状态模式
状态模式一般用来实现状态机,是状态机的一种实现方式
状态机又叫有限状态机,它有 3 个部分组成:状态、事件、动作。其中,事件也称为转移条件。事件触发状态的转移及动作的执行
实现方式
分支逻辑法
查表法
状态模式
迭代器模式
用来遍历集合对象,迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一
一个完整的迭代器模式,一般会涉及容器和容器迭代器两部分内容
为了达到基于接口而非实现编程的目的,容器又包含容器接口、容器实现类,迭代器又包含迭代器接口、迭代器实现类。容器中需要定义 iterator() 方法,用来创建迭代器。迭代器接口中需要定义 hasNext()、currentItem()、next() 三个最基本的方法
访问者模式
允许一个或者多个操作应用到一组对象上,解耦操作和对象本身
访问者模式难以理解,应用场景有限,不是特别必需
备忘录模式
在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态
主要是用来防丢失、撤销、恢复等
命令模式
命令模式将请求(命令)封装为一个对象,这样可以使用不同的请求参数化其他对象(将不同请求依赖注入到其他对象),并且能够支持请求(命令)的排队执行、记录日志、撤销等(附加控制)功能
命令模式的主要作用和应用场景,是用来控制命令的执行,比如,异步、延迟、排队执行命令、撤销重做命令、存储命令、给命令记录日志等等
解释器模式
解释器模式为某个语言定义它的语法(或者叫文法)表示,并定义一个解释器用来处理这个语法
它的代码实现的核心思想,就是将语法解析的工作拆分到各个小类中,以此来避免大而全的解析类。一般的做法是,将语法规则拆分一些小的独立的单元,然后对每个单元进行解析,最终合并为对整个语法规则的解析
中介模式
中介模式定义了一个单独的(中介)对象,来封装一组对象之间的交互。将这组对象之间的交互委派给与中介对象交互,来避免对象之间的直接交互
中介模式的设计思想跟中间层很像,通过引入中介这个中间层,将一组对象之间的交互关系(或者依赖关系)从多对多(网状关系)转换为一对多(星状关系)。原来一个对象要跟 n 个对象交互,现在只需要跟一个中介对象交互,从而最小化对象之间的交互关系,降低了代码的复杂度,提高了代码的可读性和可维护性。
观察者模式和中介模式都是为了实现参与者之间的解耦,简化交互关系。两者的不同在于应用场景上。在观察者模式的应用场景中,参与者之间的交互比较有条理,一般都是单向的,一个参与者只有一个身份,要么是观察者,要么是被观察者。而在中介模式的应用场景中,参与者之间的交互关系错综复杂,既可以是消息的发送者、也可以同时是消息的接收者
0 条评论
下一页