本期内容为自己总结归档,共分十一章,本人遇到过的面试问题会重点标记。
(若有任何疑问,可在评论区告诉我,看到就回复)
第一部分:设计模式的三大分类回顾
1.1 创建型模式:对象创建的优雅之道
创建型模式关注对象的创建机制,帮助我们以灵活、可复用的方式创建对象。
| 模式 | 核心思想 | 典型应用场景 | 关键点 |
|---|---|---|---|
| 单例模式 | 确保一个类只有一个实例 | 配置管理器、数据库连接池 | 全局访问点,线程安全 |
| 工厂方法 | 将对象创建延迟到子类 | 跨平台UI组件、支付方式 | 符合开闭原则,支持扩展 |
| 抽象工厂 | 创建相关对象族 | GUI库、跨数据库访问 | 产品族兼容性 |
| 建造者模式 | 分步构建复杂对象 | 复杂对象创建(如SQL查询) | 分离构建与表示,避免构造函数参数过多 |
| 原型模式 | 通过复制创建对象 | 游戏中的敌人复制、成本高的对象创建 | 克隆比新建更高效 |
1.2 结构型模式:构建灵活的结构
结构型模式关注如何将类或对象组合成更大的结构,同时保持结构的灵活和高效。
| 模式 | 核心思想 | 典型应用场景 | 关键点 |
|---|---|---|---|
| 适配器模式 | 转换接口,使不兼容的接口协同工作 | 集成遗留系统、第三方库 | 包装对象,提供不同接口 |
| 桥接模式 | 分离抽象与实现 | 跨平台UI、多维度变化系统 | 组合替代继承,两个维度独立变化 |
| 组合模式 | 统一处理部分-整体层次结构 | 文件系统、GUI组件树 | 树形结构,一致对待单个和组合对象 |
| 装饰器模式 | 动态添加功能 | Java I/O流、中间件链 | 组合优于继承,运行时添加功能 |
| 外观模式 | 为复杂子系统提供统一入口 | 框架API、简化复杂调用 | 简化接口,降低耦合 |
| 享元模式 | 共享细粒度对象 | 文字编辑器、游戏中的大量相似对象 | 分离内部状态和外部状态 |
| 代理模式 | 控制对象访问 | 远程代理、虚拟代理、保护代理 | 中介作用,控制访问 |
1.3 行为型模式:优雅的对象协作
行为型模式关注对象之间的职责分配和通信方式,定义对象交互的模式。
| 模式 | 核心思想 | 典型应用场景 | 关键点 |
|---|---|---|---|
| 观察者模式 | 一对多依赖,状态改变自动通知 | 事件处理系统、MVC架构 | 松耦合,事件驱动 |
| 策略模式 | 封装算法族,使其可互换 | 支付策略、排序算法 | 消除条件判断,支持运行时切换 |
| 模板方法 | 定义算法骨架,子类实现步骤 | 框架钩子、工作流程 | 控制算法结构,子类扩展细节 |
| 责任链 | 请求沿链传递,直到有对象处理 | 审批流程、过滤器链 | 解耦发送者和接收者 |
| 命令模式 | 将请求封装为对象 | 撤销/重做、事务处理 | 封装请求,支持队列和日志 |
| 状态模式 | 状态改变时改变行为 | 订单状态机、游戏角色状态 | 消除状态条件判断 |
| 访问者模式 | 不改变元素结构下定义新操作 | 编译器、文档处理 | 双重分发,集中相关操作 |
第二部分:设计模式的学习路径与原则
2.1 学习路径建议
-
理解设计原则:首先掌握SOLID原则,这是设计模式的基础。
-
从常用模式开始:先学习单例、工厂、观察者、策略、装饰器等最常用的模式。
-
动手实践:在项目中尝试应用,或通过重构现有代码来练习。
-
阅读优秀源码:学习Spring、JDK等框架中设计模式的应用。
-
理解模式意图:不要死记结构,要理解模式解决什么问题。
2.2 SOLID原则回顾
SOLID原则是面向对象设计的基石:
| 原则 | 含义 | 设计模式中的体现 |
|---|---|---|
| 单一职责 | 一个类只应有一个引起变化的原因 | 每个模式都强调职责分离 |
| 开闭原则 | 对扩展开放,对修改关闭 | 策略模式、装饰器模式等 |
| 里氏替换 | 子类必须能够替换父类 | 继承体系的设计 |
| 接口隔离 | 客户端不应依赖不需要的接口 | 适配器模式、外观模式 |
| 依赖倒置 | 依赖抽象而非具体实现 | 工厂模式、模板方法等 |
2.3 设计模式与原则的关系
| 设计原则 | 体现该原则的设计模式 |
|---|---|
| 开闭原则 | 策略模式、装饰器模式、观察者模式 |
| 单一职责 | 单例模式、工厂方法、状态模式 |
| 依赖倒置 | 工厂模式、模板方法、策略模式 |
| 接口隔离 | 适配器模式、外观模式 |
| 迪米特法则 | 外观模式、中介者模式 |
设计模式是设计原则的具体体现。例如:
-
开闭原则在策略模式中体现为可以添加新策略而不修改上下文。
-
单一职责原则在状态模式中体现为每个状态类只负责一个状态的行为。
-
依赖倒置原则在工厂模式中体现为客户端依赖抽象产品而非具体产品。
第三部分:设计模式在实际中的应用
3.1 Spring框架中的设计模式
Spring框架大量使用了设计模式,这也是它如此灵活和强大的原因之一:
| 模式 | Spring中的应用 | 说明 |
|---|---|---|
| 工厂模式 | BeanFactory, ApplicationContext | 创建和管理Bean的工厂 |
| 单例模式 | Bean的默认作用域 | 默认情况下Bean是单例的 |
| 代理模式 | Spring AOP | 基于动态代理实现切面编程 |
| 模板方法 | JdbcTemplate, RestTemplate | 定义算法骨架,子类实现细节 |
| 观察者模式 | ApplicationEvent机制 | 事件发布和监听 |
| 适配器模式 | HandlerAdapter | 处理不同类型的控制器 |
| 装饰器模式 | BeanDefinition装饰器 | 动态增强Bean定义 |
3.2 设计模式的选择策略
选择设计模式时,考虑以下问题:
-
问题是什么?:明确要解决的问题,而不是强行套用模式。
-
模式的意图是什么?:确保模式的意图与你的问题匹配。
-
模式的代价是什么?:考虑引入模式带来的复杂度。
-
是否有更简单的方案?:有时候简单的代码比模式更合适。
3.3 避免设计模式的误用
-
不要为了模式而模式:模式是手段,不是目的。
-
避免过度设计:在简单场景中使用模式会增加不必要的复杂度。
-
理解模式背后的思想:比记住UML图更重要。
-
保持代码的清晰性:模式应该让代码更清晰,而不是更晦涩。
3.4 Spring设计模式的实战价值
java
// Spring中的模板方法模式
public abstract class AbstractController {
// 模板方法
public ModelAndView handleRequest(HttpServletRequest request) {
// 1. 前置处理
preHandle(request);
// 2. 核心处理(由子类实现)
ModelAndView result = doHandle(request);
// 3. 后置处理
postHandle(request, result);
return result;
}
protected abstract ModelAndView doHandle(HttpServletRequest request);
protected void preHandle(HttpServletRequest request) {
// 通用前置处理
}
protected void postHandle(HttpServletRequest request, ModelAndView result) {
// 通用后置处理
}
}
第四部分:设计模式的未来与演进
4.1 函数式编程与设计模式
随着函数式编程的兴起,一些传统设计模式有了新的实现方式:
-
策略模式:可以使用Lambda表达式更简洁地实现。
-
观察者模式:反应式编程(如Reactor、RxJava)提供了更强大的事件流处理。
-
模板方法:可以使用函数组合替代继承。
4.2 微服务架构中的设计模式
在微服务架构中,设计模式有了新的应用:
-
外观模式:API网关作为微服务系统的统一入口。
-
观察者模式:事件驱动架构,服务间通过事件通信。
-
代理模式:服务网格(Service Mesh)中的边车代理。
4.3 设计模式的局限性
设计模式不是银弹,它们有局限性:
-
可能增加复杂度:不恰当地使用会增加系统复杂度。
-
可能过度抽象:过度抽象会导致代码难以理解。
-
语言特性影响:不同编程语言可能需要不同的模式实现。
第五部分:总结与展望
5.1 设计模式的核心价值
设计模式的核心价值在于:
-
共享词汇表:提供通用的设计语言,提高沟通效率。
-
最佳实践总结:捕获了经验丰富的开发者的智慧。
-
提高代码质量:促进可复用、可维护、可扩展的设计。
-
降低系统复杂度:通过提供经过验证的解决方案来管理复杂度。
5.2 设计模式决策树