"设计模式用不好,就是屎山的另一种形态。"
设计模式不是"越多越好",而是"刚好够用"最好。
业务小的时候,硬上模式,确实就是自找麻烦。
| 业务规模 | 正确姿势 |
|---|---|
| 小项目/原型/脚本 | 怎么快怎么来,if-else 写得清晰就行,别预支未来。 |
| 中等项目(3-6 个月生命周期) | 适度封装,出现第二次重复再抽模式,别一上来就"战略架构"。 |
| 大型/长期演进/多人协作 | 模式是"刚需",否则半年后就变成"谁动谁死"的屎山。 |
设计模式介绍:
| 大类 | 模式(11字速记) | 核心意图一句话 |
|---|---|---|
| 创建型 5 | 单例 Singleton |
全局唯一实例 |
工厂方法 Factory Method |
子类决定实例化哪个类 | |
抽象工厂 Abstract Factory |
创建一整套产品族 | |
建造者 Builder |
分步骤组装复杂对象 | |
原型 Prototype |
克隆现有对象 | |
| 结构型 7 | 适配器 Adapter |
接口不兼容转接头 |
桥接 Bridge |
抽象与实现解耦 | |
组合 Composite |
树形结构统一处理 | |
装饰 Decorator |
动态贴功能 | |
外观 Facade |
对外统一简化入口 | |
享元 Flyweight |
共享细粒度对象省内存 | |
代理 Proxy |
间接访问、控制、增强 | |
| 行为型 11 | 责任链 Chain of Responsibility |
沿链传递直到被处理 |
命令 Command |
请求封装成对象 | |
解释器 Interpreter |
小语言解释执行 | |
迭代器 Iterator |
顺序访问不暴露内部 | |
中介者 Mediator |
网状变星型降耦合 | |
备忘录 Memento |
快照保存与回滚 | |
观察者 Observer |
状态变化自动通知 | |
状态 State |
状态变行为自动切换 | |
策略 Strategy |
算法族运行时互换 | |
模板方法 Template Method |
骨架不变,子类填细节 | |
访问者 Visitor |
不改变类即可新增操作 |
观察者模式:
传统的代码不是已经可以解决以下业务了吗?为什么还要观察者设计模式呢?
public void paySuccess(String orderId){
orderDao.updateStatus(orderId, PAID); // ① 改状态
smsService.send(orderId); // ② 发送短信
mpService.push(orderId); // ③ 小程序推送
emailService.send(orderId); // ④ 发送邮件
}
为了不拖垮主程序、通知代码各自独立
-
异步 :加
@Async就能把通知放到线程池,主流程毫秒级返回 -
重试/降级 :每个监听器自己用
@Retryable或断路器,互不影响 -
测试隔离:跑订单单测时不必加载任何通知类
------加 10 种通知也不需要再碰订单代码,这就是它最大的实际作用。
责任链模式:
传统代码:
public class LeaveApproval {
public void approve(int days) {
if (days <= 1) {
System.out.println("组长审批通过,请假 " + days + " 天。");
} else if (days <= 3) {
System.out.println("经理审批通过,请假 " + days + " 天。");
} else {
System.out.println("总经理审批通过,请假 " + days + " 天。");
}
}
}
表面上看,责任链模式确实可以用 if-else 或 switch-case 实现,但它真正的价值并不在于"能不能实现",而在于"如何实现得更优雅、可扩展、易维护"。
❌ if-else 的问题在哪?
| 问题 | 说明 |
|---|---|
| 违反开闭原则 | 每新增一个审批层级(比如"总监"),你都得修改原有代码 ,增加新的 else if,这会导致类越来越臃肿。 |
| 逻辑耦合 | 所有审批逻辑都堆在一个方法里,职责不单一,后期难以维护。 |
| 无法动态调整顺序 | 如果你想让"总监"插在"经理"之前,必须改代码,而不能通过配置或运行时调整。 |
| 无法复用审批逻辑 | 如果另一个模块也需要类似的审批流程,你得复制粘贴 一套 if-else,造成代码冗余。 |
🎯 总结一句话:
责任链模式不是为了"解决能不能做",而是为了"解决怎么做得更优雅、更可扩展"。
-
如果你只是写个一次性脚本,
if-else完全够用。 -
但如果你在做的是一个需要长期维护、可能扩展的系统 ,责任链模式会让你少踩很多坑。
单例模式
应用场景:如数据库连接池、线程池等
作用:避免重复创建实例,节省资源,提供全局访问点,确保系统中只有一个实例。
实现方式:懒汉式、饿汉式、双重校验锁(DCL)(待优化)
解决问题:
- 并发量 5 k QPS,每请求新建连接会把 DB 打挂。
- 保证"同一个配置、同一个连接池实例"在 JVM 里只有一份,并且可测试、可热更新。
工厂模式
应用场景:用于封装对象,解耦合,便于管理
作用:将对象的创建过程封装起来,隐藏了创建细节,方便扩展
实现方式:简单工厂模式、工厂方法模式、抽象工厂模式
动态代理(AOP)
应用场景:事务、日志、权限、性能监控
作用:代理对象可以根据需要添加不同的逻辑,在运行时动态创建;目标对象和代理对象解耦,目标对象无需知道代理的存在;可以在不修改目标对象代码的情况下,通过代理对象添加额外的逻辑。
实现方式:
解决问题:
- 下单接口要求 30 ms 返回,但日志、幂等、监控、权限、事务五层切面叠加后,TP99 飙到 120
- 让横切逻辑"可观测、可灰度、可一键降级",同时把额外耗时压到 5 ms 以内。