设计模式概览

设计模式是解决特定问题的一系列套路,有一定的普遍性;是一套被反复使用、多数人知晓的、代码设计经验的总结。它可以提高代码的可重用性、代码的可读性和代码的可靠性以及可扩展性。

常用的设计模式有23种,5种创建型模式 (Creational Pattern)(下表中的简单工厂模式一般不算在内),7种结构型模式 (Structural Pattern),11种行为型模式 (Behavioral Pattern)

创建型模式

模式名称学习难度使用频率
单例模式 Singleton Pattern⭐☆☆☆☆⭐⭐⭐⭐☆
简单工厂模式 Simple Factory Pattern⭐⭐☆☆☆⭐⭐⭐☆☆
工厂方法模式 Factory Method Pattern⭐⭐☆☆☆⭐⭐⭐⭐⭐
抽象工厂模式 Abstract Factory Pattern⭐⭐⭐⭐☆⭐⭐⭐⭐⭐
原型模式 Prototype Pattern⭐⭐⭐☆☆⭐⭐⭐☆☆
建造者模式 Builder Pattern⭐⭐⭐⭐☆⭐⭐☆☆☆

结构型模式

模式名称学习难度使用频率
适配器模式 Adapter Pattern⭐⭐☆☆☆⭐⭐⭐⭐☆
桥接模式 Bridge Pattern⭐⭐⭐☆☆⭐⭐⭐☆☆
组合模式 Composite Pattern⭐⭐⭐☆☆⭐⭐⭐⭐☆
装饰模式 Decorator Pattern⭐⭐⭐☆☆⭐⭐⭐☆☆
外观模式 Facade Pattern⭐☆☆☆☆⭐⭐⭐⭐⭐
享元模式 Flyweight Pattern⭐⭐⭐⭐☆⭐☆☆☆☆
代理模式 Proxy Pattern⭐⭐⭐☆☆⭐⭐⭐⭐☆

行为型模式

模式名称学习难度使用频率
职责链模式 Chain of Responsibility Pattern⭐⭐⭐☆☆⭐⭐☆☆☆
命令模式 Command Pattern⭐⭐⭐☆☆⭐⭐⭐⭐☆
解释器模式 Interpreter Pattern⭐⭐⭐⭐⭐⭐☆☆☆☆
迭代器模式 Iterator Pattern⭐⭐⭐☆☆⭐⭐⭐⭐⭐
中介者模式 Mediator Pattern⭐⭐⭐☆☆⭐⭐☆☆☆
备忘录模式 Memento Pattern⭐⭐☆☆☆⭐⭐☆☆☆
观察者模式 Observer Pattern⭐⭐⭐☆☆⭐⭐⭐⭐⭐
状态模式 State Pattern⭐⭐⭐☆☆⭐⭐⭐☆☆
策略模式 Strategy Pattern⭐☆☆☆☆⭐⭐⭐⭐☆
模板方法模式 Template Method Pattern⭐⭐☆☆☆⭐⭐⭐☆☆
访问者模式 Visitor Pattern⭐⭐⭐⭐☆⭐☆☆☆☆

简单工厂模式

定义

简单工厂模式是创建型设计模式的一种,它提供了一个创建对象的接口,但不暴露对象的创建逻辑。客户端通过一个公共的接口来创建所需的对象,而不需要知道具体的创建过程。

核心思想

结构组成

  1. 抽象产品 (Abstract Product):定义产品的公共接口

  2. 具体产品 (Concrete Product):实现抽象产品接口的具体类

  3. 简单工厂 (Simple Factory):负责创建具体产品对象的工厂类

  4. 客户端 (Client):使用工厂创建产品对象

实现

形状工厂

形状工厂

数据库连接工厂

简单工厂_数据库连接工厂

日志记录器工厂

简单工厂_日志记录器工厂

总结

优缺点

优点:

1、工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离

2、客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量

3、通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

总结:可以根据产品的名字生产出对应的产品

缺点:

1、由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响;

2、使用简单工厂模式势必会增加系统中类的个数(引入新的工程类),增加了系统的复杂度和理解难度;(比如,如果想要创建梯形、椭圆形之类的图形,还需要改动Factory的代码)

3、系统拓展困难,一旦添加了新的产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的拓展和维护

4、简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构

总结:违反了单一职责原则、违反了开放闭合原则、违反了依赖倒置原则

适用场景

  1. 产品类型相对固定:当需要创建的对象类型不会频繁变化时

  2. 客户端不关心创建过程:只需要获得产品对象,不关心如何创建

  3. 创建逻辑相对简单:不涉及复杂的创建过程

  4. 需要统一管理对象创建:希望将创建逻辑集中管理

简单工厂模式是最基础的工厂模式,它通过一个工厂类来创建不同类型的产品对象。虽然它违反了开闭原则,但在产品类型相对固定的场景下,简单工厂模式能够有效地封装对象创建逻辑,降低客户端与具体产品类之间的耦合度。在实际开发中,简单工厂模式常用于创建配置对象、数据库连接、日志记录器等场景。

工厂方法模式

定义

工厂方法模式是创建型设计模式的一种,它定义了一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类中进行,从而实现了创建者和具体产品的解耦。

核心思想

结构组成

  1. 抽象产品 (Abstract Product):定义产品的公共接口

  2. 具体产品 (Concrete Product):实现抽象产品接口的具体类

  3. 抽象工厂 (Abstract Factory):声明工厂方法,返回抽象产品类型

  4. 具体工厂 (Concrete Factory):实现工厂方法,返回具体产品实例

  5. 客户端 (Client):使用抽象工厂和抽象产品

实现

交通工具工厂

交通工具工厂

数据库连接工厂

工厂方法_数据库连接

日志记录器工厂

工厂方法_日志记录器

总结

优缺点

优点:

1、用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。

2、灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。

3、典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类。

4、对扩展开放对修改关闭;解决了简单工厂的缺点问题。

总结:遵循了单一职责原则、开放闭合原则、遵循了依赖倒置原则。

缺点:

1、类的个数容易过多,增加复杂度

2、增加了系统的抽象性和理解难度

3、接口的传入参数类型需要一致,且只能对单一变化量接口使用

4、抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

总结:工厂的数量会随着产品的增加而急剧上升。

适用场景

  1. 创建对象需要大量重复代码

  2. 客户端不依赖于产品类实例如何被创建、实现等细节

  3. 一个类通过其子类来指定创建哪个对象

  4. 需要为库或框架提供扩展点

与简单工厂模式的区别

特性简单工厂模式工厂方法模式
工厂数量一个工厂类多个工厂类(每个产品一个工厂)
扩展性违反开闭原则,需要修改工厂类遵循开闭原则,只需添加新工厂类
复杂度简单,适合产品种类少的情况相对复杂,适合产品种类多的情况
职责分离工厂类职责较重每个工厂类职责单一
客户端依赖依赖具体工厂类依赖抽象工厂类
参数传递通常需要参数来决定创建哪种产品不需要参数,工厂类型决定产品类型

工厂方法模式是一种非常实用的创建型设计模式,它通过将对象的创建延迟到子类中,实现了创建者和产品的解耦。相比简单工厂模式,工厂方法模式更好地遵循了开闭原则和单一职责原则,使得系统更容易扩展和维护。在需要创建多种相关产品,且产品种类可能会增加的场景下,工厂方法模式是一个很好的选择。

抽象工厂模式

定义

抽象工厂模式是创建型设计模式的一种,它提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式也被称为Kit模式,它是工厂方法模式的进一步抽象和推广。

核心思想

结构组成

  1. 抽象工厂 (Abstract Factory):声明创建抽象产品对象的操作接口

  2. 具体工厂 (Concrete Factory):实现创建具体产品对象的操作

  3. 抽象产品 (Abstract Product):为一类产品对象声明接口

  4. 具体产品 (Concrete Product):定义具体工厂创建的产品对象

  5. 客户端 (Client):使用抽象工厂和抽象产品类声明的接口

产品族概念

产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。例如:

实现

GUI组件工厂

GUI组件工厂

游戏角色装备工厂

游戏角色装备工厂

总结

优缺点

优点:

  1. 抽象工厂模式隔离了具体类的生成,使得客户端并不需要知道什么被创建。

  2. 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一产品族中的对象;

  3. 增加新的产品族很方便(生成新的具体工厂),无需修改已有系统代码,符合开闭原则;

缺点: 增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。

适用场景

  1. 系统需要独立于产品的创建、组合和表示

  2. 系统需要由多个产品族中的一个来配置

  3. 需要强调一系列相关产品对象的设计以便进行联合使用

  4. 提供一个产品类库,只想显示接口而不是实现

与其他工厂模式的对比

特性简单工厂工厂方法抽象工厂
产品数量单一产品单一产品产品族(多个相关产品)
工厂数量一个工厂多个工厂多个工厂
工厂方法数量一个方法一个方法多个方法
扩展性违反开闭原则符合开闭原则符合开闭原则
复杂度简单中等复杂
适用场景产品种类少产品种类多产品族的创建

实际应用场景

  1. 跨平台UI框架:不同操作系统的UI组件

  2. 数据库访问层:不同数据库的连接、命令、事务对象

  3. 游戏开发:不同职业的装备、技能、属性

  4. 主题系统:不同主题的颜色、字体、图标

  5. 文档处理:不同格式的解析器、生成器、验证器

抽象工厂模式是处理产品族创建的强大工具,它通过提供一系列相关产品的创建接口,确保了产品的一致性和系统的可扩展性。虽然它增加了系统的复杂度,但在需要管理多个相关产品族的场景下,抽象工厂模式能够提供清晰的架构和良好的可维护性。在实际应用中,合理地设计产品族和工厂层次结构是成功应用这一模式的关键。

观察者模式

定义

观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

核心思想

结构组成

1. 抽象主题(Subject)

定义添加、删除和通知观察者的接口

2. 具体主题(ConcreteSubject)

实现抽象主题接口,维护观察者列表和状态

3. 抽象观察者(Observer)

定义更新接口,供主题通知时调用

4. 具体观察者(ConcreteObserver)

实现抽象观察者接口,定义具体的更新行为

实现

基础实现

观察者模式

股票价格监控系统

股票市场观察者

总结

优缺点

优点:

1、观察者和被观察者是抽象耦合的

2、建立一套触发机制。

缺点:

1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

适用场景

  1. GUI事件处理:按钮点击、窗口事件等

  2. 模型-视图架构:MVC、MVP、MVVM模式

  3. 消息系统:发布-订阅消息队列

  4. 数据绑定:数据变化自动更新UI

  5. 监控系统:系统状态监控和告警

  6. 游戏开发:事件系统、状态变化通知

观察者模式是一种强大的行为型设计模式,它通过建立一对多的依赖关系,实现了对象间的松耦合通信。该模式在GUI编程、事件处理、数据绑定等场景中应用广泛,是现代软件架构中不可或缺的设计模式之一。正确使用观察者模式可以提高代码的可维护性和扩展性,但也需要注意性能和内存管理等问题。

职责链模式

定义

职责链模式是一种行为型设计模式,它为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

核心思想

结构组成

1. 抽象处理者(Handler)

定义处理请求的接口,包含指向下一个处理者的引用

2. 具体处理者(ConcreteHandler)

实现处理请求的具体逻辑,如果不能处理则传递给下一个处理者

3. 客户端(Client)

创建处理者链并发送请求

实现

请假审批系统

请假审批系统

日志处理系统

日志处理系统

总结

优缺点

优点

  1. 解耦请求与处理: 发送者和处理者解耦,请求的发送者无需知道链的结构和具体处理者,只需将请求提交到链中。 示例:员工请假流程中,员工只需提交请假申请,无需关心审批链的具体节点(组长→经理→总监等)。

  2. 符合开闭原则: 可以动态添加、删除处理者,或调整处理顺序(灵活扩展处理链)。

  3. 符合单一职责原则:每个处理者专注于自己的职责(如校验、审批、计算等),职责清晰,代码可维护性高。

缺点

  1. 请求可能未被处理: 如果链中没有任何处理者能处理请求,且没有设置默认处理者(如链尾的 “兜底” 处理者),请求可能被忽略,导致隐性 bug。 解决方案:在链尾添加一个默认处理者(如 “无处理者” 提示)。

  2. 调试成本较高: 请求的传递路径是动态的,可能需要跟踪整个链的调用过程,尤其当链较长时,调试难度增加。 缓解方法:在处理者中添加日志记录,输出请求传递的节点信息。

  3. 性能可能受影响: 若链过长,请求需要遍历多个处理者,可能导致性能损耗(尤其是对实时性要求高的场景)。 适用场景:优先用于请求处理逻辑较简单、链长度可控的场景。

适用场景

  1. 多个对象可以处理同一请求:但具体由哪个对象处理在运行时确定

  2. 不明确指定接收者:希望向多个对象中的一个提交请求

  3. 动态指定处理者集合:可处理请求的对象集合需要动态指定

  4. 审批流程:如请假审批、采购审批等

  5. 异常处理:不同级别的异常需要不同的处理方式

  6. 日志系统:不同级别的日志需要不同的输出方式

变体模式

1. 纯职责链

每个处理者要么处理请求,要么传递给下一个处理者,不能同时进行

2. 不纯职责链

允许一个处理者处理请求后,仍然将请求传递给下一个处理者

3. 分支职责链

处理者可以根据条件选择不同的下一个处理者


职责链模式是一种强大的行为型设计模式,它通过将请求的发送者和接收者解耦,提供了一种灵活的请求处理机制。该模式特别适用于需要多级处理、审批流程、过滤器链等场景。虽然可能带来一定的性能开销,但其提供的灵活性和可扩展性使其在许多实际应用中都有重要价值。正确使用职责链模式可以使系统更加模块化、易于维护和扩展。

装饰器模式

定义

装饰器模式是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。装饰器模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

核心思想

结构组成

1. 抽象组件(Component)

定义一个对象接口,可以给这些对象动态地添加职责

2. 具体组件(ConcreteComponent)

实现抽象组件接口的具体对象

3. 抽象装饰器(Decorator)

维持一个指向组件对象的引用,并定义一个与组件接口一致的接口

4. 具体装饰器(ConcreteDecorator)

实现具体的装饰功能,给组件添加职责

实现

咖啡订购系统

咖啡订购系统

文本处理系统

文本处理系统

总结

优缺点

优点

  1. 灵活性高:装饰器模式提供了比继承更灵活的扩展方式。继承是静态的,在编译时就确定了类的功能,而装饰器模式可以在运行时动态地为对象添加或移除功能。

  2. 可维护性好:通过将不同的功能封装在不同的装饰器类中,使得代码的结构更加清晰,每个装饰器类只负责单一的功能,便于维护和修改。

  3. 复用性强:装饰器类可以被多个对象复用,不同的装饰器还可以进行组合,以实现不同的功能组合。

  4. 遵循开闭原则:对扩展开放,对修改关闭。可以在不修改现有代码的情况下,通过添加新的装饰器类来扩展系统的功能。

缺点

  1. 产生过多小对象:使用装饰器模式会产生许多小对象,每个装饰器都是一个独立的类,这会增加系统的复杂性和理解难度。

  2. 调试困难:由于装饰器的嵌套使用,可能会导致调试时难以跟踪对象的行为,特别是当装饰器链较长时。

适用场景

  1. 动态添加功能:需要在不修改现有代码的情况下扩展对象功能

  2. 功能组合:需要将多个功能进行组合使用

  3. 避免继承爆炸:当用继承扩展功能会导致子类数量急剧增加时

  4. 临时功能:需要临时给对象添加一些功能

  5. 插件系统:实现可插拔的功能模块

  6. 数据处理管道:构建数据处理的流水线

变体模式

1. 透明装饰器

装饰器和组件实现相同的接口

2. 半透明装饰器

装饰器除了实现组件接口外,还可以定义新的方法

3. 函数式装饰器

使用函数而非类来实现装饰功能


装饰器模式是一种强大的结构型设计模式,它提供了一种灵活的方式来扩展对象的功能,而无需修改其结构。该模式特别适用于需要动态添加功能、避免继承爆炸、构建处理管道等场景。虽然可能增加系统复杂性,但其提供的灵活性和可组合性使其在许多实际应用中都有重要价值。正确使用装饰器模式可以使系统更加模块化、易于扩展和维护。