Skip to content

设计模式 从零到生产级掌握

设计模式最容易学偏:背了一堆名字,写代码时不是不会用,就是到处乱用。真正的掌握标准不是“能说出定义”,而是能判断:问题的变化点在哪里,不用模式会怎样,用了模式解决了什么,又增加了什么成本。

一句话建立主线:

设计模式是隔离变化点的经验集合。它不是为了让代码看起来复杂,而是让真实会变化的部分更容易扩展,让稳定的主流程更少被修改。

学习目标

学完这一页,你要能做到:

  1. 解释创建型、结构型、行为型模式分别解决什么问题。
  2. 判断一个场景是否真的需要设计模式。
  3. 解释不用模式时会出现什么维护问题。
  4. 解释使用模式后调用链怎么变化。
  5. 解释每个模式的代价和误用后果。
  6. 能把模式落到订单、支付、通知、采集、导入、权限、审批、第三方接口等商业场景。
  7. 能结合 Spring、JDK 和项目代码解释模式,而不是只背定义。
  8. 能在面试中先讲业务问题,再讲模式解决方式,最后讲边界。

如果要按“零基础能看懂、原理能讲清、项目能落地、面试能回答、线上能排查”的标准验收,请配合阅读 设计模式从零到精通验收清单。本页负责建立主线,验收清单负责把创建型、结构型、行为型模式按变化点、Demo、商业场景、误用后果和排查逐项拆开。

先理解变化点

设计模式不是从“我要用哪个模式”开始,而是从“哪里会变”开始。

mermaid
flowchart TD
    A["阅读业务需求"] --> B["找变化点"]
    B --> C{"变化是否真实存在"}
    C -- "否" --> D["先直接写清楚"]
    C -- "是" --> E{"变化是否会持续发生"}
    E -- "否" --> D
    E -- "是" --> F["选择合适模式隔离变化"]
    F --> G["保留清晰调用链和测试"]

常见变化点:

变化点常见模式示例
创建哪种对象会变工厂支付渠道、消息发送器
对象参数很多建造者查询条件、导出配置
全局唯一资源单例配置、线程池、连接池
调用前后要增强代理事务、权限、日志
原接口不兼容适配器第三方医院接口
能力要叠加装饰器IO 流、数据脱敏包装
多种规则切换策略折扣、计费、文件解析
一件事通知多方观察者本地事件、领域事件
流程固定步骤可变模板方法数据导入、文件处理
多步骤顺序处理责任链校验链、过滤器链

三大分类怎么理解

mermaid
flowchart TD
    A["设计模式"] --> B["创建型"]
    A --> C["结构型"]
    A --> D["行为型"]
    B --> E["对象怎么创建"]
    C --> F["对象怎么组合或增强"]
    D --> G["对象之间怎么协作"]
分类解决的问题代表模式
创建型对象创建逻辑复杂或会变化单例、工厂、建造者
结构型类或对象组合关系需要调整代理、装饰器、适配器
行为型多个对象之间的流程和规则协作策略、观察者、模板方法、责任链

创建型模式

单例模式

适合全局唯一资源,例如线程池、配置中心客户端、连接池管理器。

不使用会怎样:

  1. 多处重复创建昂贵对象。
  2. 状态不一致。
  3. 资源无法统一关闭和监控。

Spring 中大多数 Bean 默认是单例,但这是容器级单例,不等于手写 JVM 全局单例。

java
public class IdGenerator {
    private static final IdGenerator INSTANCE = new IdGenerator();

    private IdGenerator() {
    }

    public static IdGenerator getInstance() {
        return INSTANCE;
    }

    public long nextId() {
        return System.currentTimeMillis();
    }
}

误用后果:把有用户状态、请求状态的对象做成单例,会产生线程安全和数据串扰问题。

工厂模式

适合“创建哪种实现”会变化的场景。

mermaid
flowchart TD
    A["业务传入 type"] --> B["Factory"]
    B --> C["AliPayService"]
    B --> D["WechatPayService"]
    B --> E["UnionPayService"]

支付工厂 Demo:

java
public interface PayService {
    String channel();

    void pay(PayCommand command);
}

@Component
public class PayFactory {
    private final Map<String, PayService> serviceMap;

    public PayFactory(List<PayService> services) {
        this.serviceMap = services.stream()
            .collect(Collectors.toMap(PayService::channel, service -> service));
    }

    public PayService get(String channel) {
        PayService service = serviceMap.get(channel);
        if (service == null) {
            throw new IllegalArgumentException("不支持的支付渠道");
        }
        return service;
    }
}

不使用会怎样:到处 if ("ALI") new AliPayService(),新增渠道要改很多地方。

建造者模式

适合参数很多、可选项很多、构建过程需要校验的对象。

java
OrderQuery query = OrderQuery.builder()
    .status(1)
    .startTime(start)
    .endTime(end)
    .pageNo(1)
    .pageSize(20)
    .build();

不使用会怎样:构造器参数很长,调用者容易传错顺序;对象创建规则散落在各处。

误用后果:只有两三个简单字段也强行 Builder,会让代码变啰嗦。

结构型模式

代理模式

代理强调“控制访问或统一增强”。

mermaid
flowchart TD
    A["调用方"] --> B["代理对象"]
    B --> C["开启事务/权限/日志"]
    C --> D["目标对象"]
    D --> E["提交或回滚/记录结果"]

Spring 事务就是典型代理:

  1. 外部调用进入代理对象。
  2. 代理开启事务。
  3. 调用目标方法。
  4. 方法成功提交,异常回滚。

为什么同类自调用事务失效:因为没有经过代理对象。

装饰器模式

装饰器强调“不改原类,动态叠加能力”。

Java IO:

java
InputStream input = new BufferedInputStream(
    new FileInputStream("data.txt")
);

FileInputStream 提供文件读取能力,BufferedInputStream 叠加缓冲能力。它们关注的是能力叠加,不是访问控制。

适配器模式

适配器解决接口不兼容。

mermaid
flowchart TD
    A["统一业务接口"] --> B["医院 A 适配器"]
    A --> C["医院 B 适配器"]
    B --> D["医院 A 原始接口"]
    C --> E["医院 B 原始接口"]

医疗平台对接不同医院时很常见:

java
public interface PatientClient {
    PatientDTO getPatient(String patientId);
}

@Component
public class HospitalAAdapter implements PatientClient {
    private final HospitalAApi api;

    public PatientDTO getPatient(String patientId) {
        HospitalAResponse response = api.query(patientId);
        return new PatientDTO(response.getPid(), response.getName());
    }
}

适配器里不要写复杂业务规则。它主要做协议、字段、错误码转换。

行为型模式

策略模式

策略解决“同一件事有多种做法”。

mermaid
flowchart TD
    A["下单"] --> B["选择优惠策略"]
    B --> C["会员折扣"]
    B --> D["满减"]
    B --> E["新人券"]

策略模式不是为了消灭所有 if。只有规则会持续扩展时才值得拆。

java
public interface DiscountStrategy {
    String type();

    BigDecimal discount(BigDecimal amount);
}

观察者模式

观察者适合进程内事件通知。

mermaid
flowchart TD
    A["订单创建成功"] --> B["发布本地事件"]
    B --> C["发站内信"]
    B --> D["写操作日志"]
    B --> E["刷新本地缓存"]

注意:观察者不等于 MQ。跨服务可靠通知、削峰、重试、持久化,应该用消息队列。

模板方法模式

模板方法固定流程骨架,把变化步骤交给子类。

java
public abstract class ImportTemplate {
    public final void importData(File file) {
        checkFile(file);
        List<String> rows = readRows(file);
        List<Object> data = parse(rows);
        validate(data);
        save(data);
    }

    protected abstract List<Object> parse(List<String> rows);

    protected abstract void save(List<Object> data);
}

适合数据导入、文件解析、报表生成这类流程顺序稳定的场景。

责任链模式

责任链适合多个处理器按顺序处理请求。

mermaid
flowchart TD
    A["创建订单请求"] --> B["参数校验"]
    B --> C["库存校验"]
    C --> D["价格校验"]
    D --> E["风控校验"]
    E --> F["创建订单"]

Demo:

java
public interface OrderCheckHandler {
    void check(CreateOrderCommand command);
}

@Service
public class OrderCreateService {
    private final List<OrderCheckHandler> handlers;

    public void create(CreateOrderCommand command) {
        for (OrderCheckHandler handler : handlers) {
            handler.check(command);
        }
        saveOrder(command);
    }
}

链路过长时必须有日志,否则线上排查会很痛苦。

商业项目组合

场景推荐组合原因
支付渠道工厂 + 策略工厂找渠道,策略执行支付
订单创建责任链 + 策略校验链有顺序,不同优惠策略可替换
医院接口接入适配器 + 策略适配不同协议,按医院选择实现
数据导入模板方法 + 责任链流程固定,校验可插拔
权限和事务代理统一增强目标方法
本地业务事件观察者一件事发生后通知多个本地处理器
文件流处理装饰器动态叠加缓冲、压缩、加密能力

过度设计怎么识别

mermaid
flowchart TD
    A["想引入模式"] --> B{"是否有多个实现"}
    B -- "否" --> C{"短期是否确定会扩展"}
    C -- "否" --> D["不要急着抽象"]
    B -- "是" --> E{"抽象是否减少修改面"}
    E -- "是" --> F["可以引入"]
    E -- "否" --> D

过度设计表现:

  1. 一个实现也抽接口、工厂、策略。
  2. 需求还不稳定就抽象。
  3. 为了模式拆出大量小类,调用链难追。
  4. 所有业务事件化,排查不知道谁处理了。
  5. 模式没有减少修改面,只是增加文件数量。

好的设计应该让新人更容易理解变化点,而不是迷路。

面试标准回答

怎么理解设计模式

text
设计模式是常见设计问题的经验总结,核心是识别变化点并隔离变化。它不是为了套 UML 或让代码复杂,而是在变化真实存在、扩展会持续发生时,让新增功能少改老代码。同时也要避免过度设计,简单稳定的业务直接写清楚更好。

工厂和策略怎么配合

text
工厂负责根据类型找到具体策略对象,策略负责执行业务逻辑。比如支付场景中,工厂根据支付渠道找到支付宝、微信或银联策略,业务层只依赖统一 PayService 接口,新增渠道时新增实现即可,尽量少改原有流程。

代理和装饰器区别

text
代理和装饰器结构上都可能包一层对象,但意图不同。代理强调访问控制或横切增强,比如事务、权限、远程代理;装饰器强调能力叠加,比如 Java IO 中给输入流增加缓冲、压缩或加密能力。

责任链适合什么场景

text
责任链适合一组有顺序、职责单一、可插拔的处理步骤,比如订单创建校验、网关过滤器、Spring Security 过滤器链。它能让每个处理器独立扩展,但链路过长时要有顺序管理、异常策略和日志,否则排查困难。

关联知识点

模式继续学习
从零到精通验收设计模式从零到精通验收清单
商业场景训练营设计模式商业场景训练营
单例单例模式
工厂工厂模式
建造者建造者模式
代理代理模式
装饰器装饰器模式
适配器适配器模式
策略策略模式
观察者观察者模式
模板方法模板方法模式
责任链责任链模式
面试题设计模式面试题

本章小结

设计模式的最终目标不是“代码里用了多少模式”,而是“变化来了是否容易改”。真正生产级的设计模式能力,是能看到业务变化点,能克制不必要抽象,也能在支付、订单、采集、导入、审批、权限、第三方接口这些真实场景中选择合适的模式。