# 什么是设计模式?请简述其作用。
7 min read
Table of Contents
什么是设计模式?请简述其作用。
【核心定义】 设计模式是一套被反复使用、经过分类编目的、用于解决软件设计中特定问题的可复用解决方案,它代表了最佳实践,是面向对象软件设计的经验总结。
【关键要点】
- 本质是经验抽象:设计模式并非具体代码,而是对特定场景下通用设计问题的抽象描述,包括问题背景、解决方案及效果。
- 核心价值在于解耦与复用:通过提供标准化的设计结构,降低系统模块间的耦合度,提升代码的可维护性、可扩展性和可复用性。
- 分类明确:通常分为创建型(如工厂、单例)、结构型(如适配器、代理)和行为型(如观察者、策略)三大类,每类解决不同维度的设计问题。
【深度推导/细节】
- 解决的核心矛盾:在软件复杂度增长与开发维护成本之间的矛盾。当需求频繁变更或系统规模扩大时,随意堆砌的代码会变得难以维护。设计模式通过预定义的角色与交互关系,强制约束了代码的组织方式,从而将变化隔离在局部。
- 以“开闭原则”为例的逻辑拆解:
- 问题:系统需要支持新功能,但修改原有代码可能引入风险。
- 模式应用:采用策略模式。
- 逻辑步骤:
- Step 1: 定义一个策略接口,声明通用算法。
- Step 2: 将系统中可变的算法部分抽离,实现为多个独立的策略类。
- Step 3: 在上下文类中持有策略接口的引用,而非具体实现。
- Step 4: 当需要新增算法时,只需实现新的策略类并注入上下文,无需修改任何原有策略类或上下文的代码。
- 结果:系统对扩展开放,对修改关闭,完美体现了设计模式的核心价值。
【关联/对比】
- 设计模式 vs. 框架/库:设计模式是概念性的指导方案,语言无关;框架(如Spring)是半成品的应用骨架,库(如Apache Commons)是具体可调用的代码集合。框架中大量使用了设计模式。
- 设计模式 vs. 设计原则:设计原则(如SOLID)是更抽象、更高层的指导思想;设计模式是这些原则在特定场景下的具体实现和体现。例如,工厂模式体现了“依赖倒置”原则。
『面试官追问』
- 请结合项目实际,举例说明你用过哪些设计模式?解决了什么问题?(高频)
- 单例模式的双重检查锁为什么要加
volatile?饿汉式和懒汉式各有何优劣? - Spring框架中大量使用了哪些设计模式?(如工厂模式创建Bean、代理模式实现AOP、模板方法模式定义流程等)
- 设计模式会不会导致过度设计?如何权衡?
【直击痛点】
- “23种”经典模式:GoF(四人帮)在《设计模式:可复用面向对象软件的基础》一书中归纳了23种基础模式,这是面试常考的数字。它代表了早期对面向对象设计经验的经典总结,但并非上限,后续还有如 MVC、依赖注入等更多模式被广泛认可。
- 模式的“适用性”:每种模式都有明确的适用场景。滥用模式(如在简单场景使用复杂模式)会导致代码不必要的复杂化,这正是“过度设计”的痛点。关键在于识别出代码中存在的“坏味道”(如大量if/else、类职责过重),再对症下药地选用模式。
【逻辑复现】(以面试高频的单例模式-双重检查锁为例)
- 目标:实现线程安全且高效的懒加载单例。
- 逻辑步骤:
- Step 1: 私有化构造函数,防止外部
new。 - Step 2: 声明一个
private static volatile的实例变量。 - Step 3: 提供公共的
public static获取方法。 - Step 4: 在方法内,首先进行第一次检查(
if (instance == null)),如果非空则直接返回,避免每次进入同步块,提升性能。 - Step 5: 如果为null,则进入同步代码块(
synchronized)。 - Step 6: 在同步块内进行第二次检查,防止在等待锁期间已有其他线程完成了初始化。
- Step 7: 确认实例为null后,执行初始化,并赋值给变量。
volatile关键作用:禁止指令重排,确保其他线程在读取instance时,看到的是一个完全初始化好的对象,避免拿到一个半初始化的对象(DCL失效问题)。
- Step 1: 私有化构造函数,防止外部
【版本差异/演进】
- 随着编程范式和语言特性的发展,设计模式的应用也在演变。例如:
- Java中的枚举(
Enum)是实现单例模式的最佳实践之一,它由JVM保证线程安全和反序列化安全,比传统的DCL更简洁安全。 - 函数式编程的兴起,使得策略模式、命令模式等可以通过Lambda表达式更简洁地实现。
- IoC容器(如Spring)的普及,使得工厂模式的应用从显式编码转变为容器配置和管理。
- Java中的枚举(