设计模式
相关源文件
介绍
设计模式是软件设计中常见问题的可重用解决方案。本文档全面概述了与后端架构相关的设计模式,解释了它们的原则、类别和实现策略。设计模式有助于提高代码的可维护性、灵活性和可重用性,同时减少开发时间和潜在的错误。
有关领域驱动设计等特定实现方法论的信息,请参见设计方法论。
设计模式原则
设计模式的有效性源于指导其实施的六个基本原则。理解这些原则对于正确应用模式至关重要。
设计模式的六大原则
| 原则 | 描述 |
|---|
| 开闭原则 | 软件实体应对扩展开放,对修改关闭。 |
| 里氏替换原则 | 超类对象应可被子类对象替换,而不影响程序。 |
| 依赖倒置原则 | 依赖抽象,而非具体。高层模块不应依赖于低层模块。 |
| 接口隔离原则 | 多个特定接口优于一个通用接口。 |
| 迪米特法则 (最少知识原则) | 一个对象应尽可能少地了解其他对象。 |
| 组合优于继承 | 在设计可重用代码时,优先使用对象组合而非类继承。 |
来源: README.md746-752
设计模式的分类
设计模式根据其目的和范围可分为三大类。
来源: README.md754-757
23种常用设计模式
由“四人帮”(Gamma、Helm、Johnson和Vlissides)最初记录的23种设计模式为各种软件设计挑战提供了解决方案。
创建型模式
侧重于对象创建机制,尝试以适合情况的方式创建对象。
- 工厂方法:创建对象,但无需指定要创建的具体类
- 抽象工厂:创建相关对象的家族
- 建造者:将对象的构建与其表示分离
- 原型:通过复制现有对象来创建对象
- 单例:确保类只有一个实例,并提供对其的全局访问点
结构型模式
处理对象组合,创建对象之间的关系以形成更大的结构。
- 适配器模式:允许不兼容的接口协同工作
- 桥接:将抽象与其实现分离
- 组合:将对象组合成树形结构以表示部分-整体层次结构
- 装饰:动态地向对象添加职责
- 外观:为复杂子系统提供一个简化接口
- 享元:通过共享高效支持大量相似对象
- 代理:为另一个对象提供一个替代品以控制对其的访问
行为型模式
侧重于对象间的通信,对象如何交互和分配职责。
- 职责链:沿处理程序链传递请求
- 命令模式:将请求封装为对象
- 解释器:实现一种专门的语言
- 迭代器:提供对聚合对象元素的顺序访问
- 中介者:定义类之间简化的通信
- 观察者模式:定义对象之间的一对多依赖关系
- 状态:允许对象在内部状态改变时改变其行为
- 策略:定义一系列算法,将每个算法封装起来,并使它们可以互换
- 模板方法:在方法中定义算法的骨架,将某些步骤推迟到子类
- 访问者:表示要在对象结构元素上执行的操作
来源: README.md754-757
应用场景
理解何时何地应用设计模式与了解模式本身同样重要。下表概述了常见的框架及其对设计模式的使用。
JDK中的设计模式
来源: README.md760-786
流行框架中的设计模式
Spring 框架。
Spring在其架构中大量依赖设计模式
- 依赖注入 - IoC原则的实现
- 代理模式 - 在Spring AOP中使用
- 工厂模式 - 用于创建bean的BeanFactory
- 模板方法 - JdbcTemplate、RestTemplate等
- 单例与原型 - 默认的bean作用域
- 观察者模式 - Spring事件系统
MyBatis框架
MyBatis也采用了多种设计模式
- 建造者模式 - SqlSessionFactoryBuilder
- 工厂模式 - SqlSessionFactory
- 代理模式 - 用于动态mapper实现的MapperProxy
- 模板方法 - BaseExecutor及其子类
- 策略模式 - 多种执行器实现
来源: README.md785-786
关键设计模式详解
单例模式
单例模式确保一个类只有一个实例,并提供对该实例的全局访问点。这对于配置管理器或连接池等需要共享的资源非常有用。
实现方法
- 饿汉式初始化:在类加载时创建实例
- 双重检查锁定懒汉式初始化:在首次访问时创建实例,并提供线程安全
- 基于枚举的单例:防止序列化和反射带来的问题
基于枚举的单例Java示例
来源: README.md789-791
职责链模式
职责链模式沿处理程序链传递请求。收到请求后,每个处理程序决定是处理请求还是将其传递给链中的下一个处理程序。
该模式常用于
- Java Web应用程序中的Servlet过滤器
- UI框架中的事件处理
- Express.js等Web框架中的中间件
- 不同的日志记录器处理不同严重级别的日志框架
来源: README.md794
MVC模式
模型-视图-控制器 (MVC) 模式将应用程序分为三个主要组件
- 模型:管理应用程序的数据、逻辑和规则
- 视图:向用户显示信息
- 控制器:处理并响应事件(通常来自用户),并可能触发模型更改
MVC广泛应用于Web应用程序和GUI框架,以分离关注点并提高可维护性。
来源: README.md796-798
控制反转 (IoC)
IoC颠覆了应用程序的传统控制流。应用程序代码不再控制流程,而是由外部系统(如框架)接管控制。
主要优势
- 解耦:组件更加独立
- 可测试性:依赖项可以轻松模拟
- 灵活性:无需修改代码即可替换组件
- 专注:开发者专注于业务逻辑,而非基础设施
来源: README.md800-805
面向切面编程 (AOP)
AOP通过将横切关注点(如日志、安全、事务)与业务逻辑分离来补充OOP。
AOP核心概念
- 切面:跨多个类的关注点的模块化
- 连接点:程序执行期间可以插入切面的点
- 通知:切面在特定连接点处采取的操作
- 切入点:匹配连接点的表达式,用于确定是否需要运行通知
Spring AOP实现
Spring AOP使用JDK动态代理或CGLIB代理
- 当目标对象实现至少一个接口时,使用JDK动态代理
- 当目标对象未实现任何接口时,使用CGLIB代理
来源: README.md807-816
设计模式的UML
统一建模语言 (UML) 为可视化设计模式及其关系提供了标准化符号。UML图有助于记录模式实现并将设计传达给团队成员。
对于设计模式,最常用的UML图包括
- 类图:显示类、接口及其关系的静态结构
- 序列图:演示对象随时间推移的交互
- 活动图:描绘活动之间的工作流或控制流程
来源: README.md819
微服务架构
微服务是一种架构风格,它将应用程序构建为一组松散耦合的服务。虽然微服务架构本身不是传统意义上的设计模式,但它融入了许多设计模式。
康威定律
康威定律指出:“组织设计的系统会模仿其沟通结构。” 该原则在微服务中尤其重要
- 沟通良好的团队将构建良好集成的系统
- 单个任务可以在有限时间内完成,但完美是不可能的
- 独立的子系统降低了沟通成本
- 大型系统倾向于分解成更小的子系统
来源: README.md821-830
设计模式选择指南
为您的应用程序选择设计模式时,请考虑以下标准
- 问题适用性:模式应解决您的特定问题
- 上下文兼容性:考虑您的应用程序的上下文和约束
- 性能影响:某些模式会引入性能开销
- 复杂性权衡:模式不应增加不必要的复杂性
- 团队熟悉度:您的团队应理解该模式或能够学习它
- 未来灵活性:模式应能适应预期的未来变化
结论
设计模式为重复出现的设计问题提供了久经考验的解决方案。通过理解并正确应用设计模式,您可以创建更具可维护性、灵活性和健壮性的软件。然而,设计模式不应在不适用之处强行使用——它们是需要审慎使用的工具,而非目标本身。
有关领域驱动设计或Actor模型等特定实现方法论,请参阅设计方法论文档。