什么是设计模式?它能带来哪些好处?

#中间件#面试八股

什么是设计模式?它能带来哪些好处?

结论先行:设计模式(Design Pattern)是对"某个场景下反复出现的设计问题"的成熟解法模板,不是可以直接 import 的代码。它真正解决的是两件事:把变化点从稳定结构里挤出去,以及让团队用同一个词指代同一个结构。

1. 拆开定义:三个要素

一个模式必须同时说清三件事,缺一个就退化成"代码片段":

要素回答什么反例(只有代码没有模式)
场景(Context)在什么约束下用看到 Map 就说是策略模式
问题(Problem)哪些力在互相拉扯只说"为了解耦",不说解耦什么
方案(Solution)用什么结构平衡这些力贴一段类图,讲不出权衡

面试里比较稳的说法是:「模式是在特定上下文中,对重复出现的设计问题的可复用解决思路,它描述的是对象之间的关系,而不是某段具体实现。」

2. 模式、算法、框架不是一回事

概念回答的问题形态例子
算法(Algorithm)怎么把输入算成输出步骤序列快排、Dijkstra
数据结构(Data Structure)数据怎么存内存布局红黑树、跳表
设计模式(Pattern)对象怎么组织、职责怎么分类/对象关系责任链、观察者
框架(Framework)骨架由谁定、谁被调用可运行的半成品Spring、Netty
架构风格(Style)系统怎么分层、怎么部署拓扑与约束分层、事件驱动、微服务

一句话记:算法管计算,数据结构管存储,模式管关系,框架管控制反转。

3. 好处一:把"会变的部分"圈出来

以订单下单为例,稳定的是主流程,易变的是各类规则:

           ┌──────────────────────────────┐
  下单主流程 │ 校验 → 计价 → 锁库存 → 落单 → 通知 │   ← 半年不动
           └──────────────────────────────┘
                ▲          ▲          ▲
                │          │          │
           ┌────┴───┐ ┌────┴────┐ ┌───┴─────┐
           │ 计价规则 │ │ 库存策略 │ │ 通知渠道 │   ← 每周都在加
           └────────┘ └─────────┘ └─────────┘

把三个易变点抽成接口(策略 / 责任链 / 观察者),主流程只依赖接口。以后加一个"直播专享价",动的是插件,不是主流程——这就是**开闭原则(Open-Closed Principle)**在工程里的具体样子。

4. 好处二:模式名是团队的压缩词汇

你想表达的意思用模式名一句话省掉的解释
多层审批,每层都可能处理或放行"这里走责任链"不用画三层 if 的流程图
订单状态流转,每个状态行为不同"用状态模式"不用解释为什么不用 switch
事件发生了,多个下游各自关心"发个观察者事件"不用逐个打电话通知
多种计费规则可切换"抽成策略"不用争论要不要写 if-else

新人听到"责任链"就能立刻想到"链表 + 命中即停 + 可能穿透到底",沟通成本被压到接近零。这也是模式最被低估的收益。

5. 好处三:约束实现方式,减少踩坑

模式自带"标准骨架",照着写不容易漏掉关键点。比如建造者(Builder)解决了构造器参数爆炸:

public final class Order {
    private final long userId;
    private final String sku;
    private final int qty;
    private final String coupon;
    private final boolean gift;

    private Order(Builder b) {
        this.userId = b.userId;
        this.sku = b.sku;
        this.qty = b.qty;
        this.coupon = b.coupon;
        this.gift = b.gift;
    }

    public static class Builder {
        private final long userId;
        private final String sku;
        private int qty = 1;          // 可选参数给默认值
        private String coupon;
        private boolean gift;

        public Builder(long userId, String sku) {   // 必填项进构造器
            this.userId = userId;
            this.sku = sku;
        }

        public Builder qty(int q) { this.qty = q; return this; }
        public Builder coupon(String c) { this.coupon = c; return this; }
        public Builder gift(boolean g) { this.gift = g; return this; }

        public Order build() {
            if (qty <= 0) {
                throw new IllegalArgumentException("qty 必须大于 0");
            }
            return new Order(this);
        }
    }
}

// 调用:链式赋值,参数顺序不再靠记忆
Order o = new Order.Builder(1001L, "SKU-9527").qty(2).gift(true).build();

收益是具体的:必填/可选分离、校验集中在 build()、对象对外不可变。

6. 代价:模式不是越多越好

  • 过度设计:只有三个分支就上"策略 + 工厂 + 注册表 + 配置中心",读代码要跳五个文件。
  • 间接层成本:多一层接口就多一次跳转,栈更深、日志更难串、调试要打好几个断点。
  • 黑话风险:团队对模式理解不一致时,"这里用桥接"反而制造误解。

判断标准很朴素:变化已经发生,或者有明确证据即将发生,才值得抽。只是"感觉以后可能会变",先写直白代码。

7. 23 种模式的分类

分类关注点包含模式
创建型(Creational)对象怎么造单例、工厂方法、抽象工厂、建造者、原型
结构型(Structural)类与对象怎么组合代理、适配器、桥接、组合、装饰器、外观、享元
行为型(Behavioral)职责怎么分派、怎么协作责任链、命令、解释器、迭代器、中介者、备忘录、观察者、状态、策略、模板方法、访问者

8. 常见追问

Q:设计模式是银弹吗? 不是。它是对既有经验的归纳,不是发明。用错场景的模式比不用更糟——比如给只有一种实现的接口硬套抽象工厂。

Q:Java 新特性会不会让模式消失? 部分会被语言特性吸收:函数式接口和 lambda 让"策略/命令"可以只写一个方法引用;enum 让单例几乎零成本;record 让不可变值对象不用手写建造者。但结构性问题仍在——需要运行时替换实现、需要横切增强时,代理和装饰器依然要写。

Q:面试怎么答才不像背书? 给一个自己改过的场景:「报表导出原来是一坨 if-else,新增渠道要改主流程还容易漏,后来抽成策略 + 注册表,新增渠道只加一个类和一个配置项」,再补一句代价「类多了,但渠道确实每周都在加」。有前后对比、有权衡,就是真实经验。

小结

  • 模式 = 场景 + 问题 + 方案,描述对象关系,不是代码模板。
  • 三大收益:隔离变化、统一团队词汇、用标准骨架少踩坑。
  • 三大代价:过度设计、间接层、黑话;是否抽象看"变化是否真的发生"。
  • 23 种按创建、结构、行为三类记,答题时先讲分类再讲具体。
笔记加载中…