设计模式与软件架构学习笔记
从设计原则到经典模式,再到架构分层与微服务。每节讲清"什么场景用、怎么实现、有什么坑"。
1 · 设计原则
1.1 SOLID
S — 单一职责(Single Responsibility Principle)
一个类或函数应该只负责一件事。判断标准:如果这个类因为两个不同的原因需要修改,就违反了 SRP。
反面例子:一个 UserService 既处理登录,又处理订单,又发邮件。应该拆成 AuthService、OrderService、EmailService。
O — 开闭原则(Open-Closed Principle)
对扩展开放,对修改关闭。
例如支付系统,不要写成:
if (type == "alipay") { ... }
else if (type == "wechat") { ... }
应该抽象出 PaymentStrategy 接口,新增支付方式时只需新增实现类。
L — 里氏替换(Liskov Substitution Principle)
子类必须能替换父类而不影响程序正确性。
反面例子:Square extends Rectangle,但正方形的 setWidth 和 setHeight 会互相影响,破坏矩形约定。
I — 接口隔离(Interface Segregation Principle)
不要强迫客户端依赖它们不需要的方法。
反面例子:一个 Worker 接口有 work() 和 eat(),但机器人只需要 work(),却不得不实现 eat()。
D — 依赖倒置(Dependency Inversion Principle)
高层模块不应该依赖低层模块,二者都应依赖抽象。
例如:服务层依赖 UserRepository 接口,而不是直接依赖 MySQLUserRepository。
1.2 其他原则
- DRY:Don't Repeat Yourself,消除重复代码
- KISS:Keep It Simple, Stupid,简单即美
- YAGNI:You Aren't Gonna Need It,不要为可能用不到的功能提前设计
- 组合优于继承:优先用组合实现复用,继承是强耦合
2 · 创建型模式
2.1 单例模式(Singleton)
保证一个类只有一个实例。
饿汉式(线程安全,类加载时创建):
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
懒汉式 + 双重检查锁:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
为什么用 volatile? 防止指令重排序导致返回未初始化完成的对象。
注意点:反射和序列化会破坏单例,生产环境可用枚举单例或静态内部类。
2.2 工厂方法(Factory Method)
定义创建对象的接口,让子类决定实例化哪个类。
interface LoggerFactory {
Logger createLogger();
}
class FileLoggerFactory implements LoggerFactory {
public Logger createLogger() { return new FileLogger(); }
}
class DBLoggerFactory implements LoggerFactory {
public Logger createLogger() { return new DBLogger(); }
}
2.3 抽象工厂(Abstract Factory)
创建一系列相关对象(产品族)。
例如 UI 组件:Windows 风格的 Button + TextBox,Mac 风格的 Button + TextBox。
interface UIFactory {
Button createButton();
TextBox createTextBox();
}
2.4 建造者模式(Builder)
当对象构造过程复杂、参数多时,用 Builder 一步步构建。
HttpRequest request = new HttpRequest.Builder()
.url("https://api.example.com")
.method("POST")
.header("Content-Type", "application/json")
.body("{}")
.build();
2.5 原型模式(Prototype)
通过复制已有对象创建新对象。
class Document implements Cloneable {
public Document clone() throws CloneNotSupportedException {
return (Document) super.clone();
}
}
注意深拷贝 vs 浅拷贝:浅拷贝只复制引用,深拷贝会递归复制对象内部。
3 · 结构型模式
3.1 适配器模式(Adapter)
把不兼容的接口转成兼容接口。
类比:Type-C 转 HDMI 转接头。
// 旧接口
class OldPrinter {
void oldPrint(String s) { ... }
}
// 目标接口
interface Printer {
void print(String s);
}
// 适配器
class PrinterAdapter implements Printer {
private OldPrinter old;
public void print(String s) { old.oldPrint(s); }
}
3.2 装饰器模式(Decorator)
动态给对象加功能,比继承灵活。
interface Coffee {
double cost();
}
class SimpleCoffee implements Coffee {
public double cost() { return 10; }
}
class MilkDecorator implements Coffee {
private Coffee coffee;
public double cost() { return coffee.cost() + 2; }
}
Java IO 流大量用了装饰器:BufferedInputStream(new FileInputStream("a.txt"))。
3.3 代理模式(Proxy)
控制对真实对象的访问。
类型:
- 静态代理:编译期确定代理类
- 动态代理:运行期生成代理(JDK 动态代理、CGLIB)
- 远程代理:RPC 调用
- 虚拟代理:懒加载
- 保护代理:权限控制
Spring AOP 底层就是动态代理。
3.4 外观模式(Facade)
为一组复杂子系统提供简单统一的接口。
例如:
class OrderFacade {
void placeOrder(Order order) {
inventoryService.check(order);
paymentService.pay(order);
shippingService.ship(order);
}
}
3.5 桥接模式(Bridge)
分离抽象和实现,让它们独立变化。
例如:图形 Shape 和颜色 Color 是两个维度。不用为每种形状 × 颜色都建一个类,而是让 Shape 持有 Color 引用。
3.6 组合模式(Composite)
统一处理单个对象和对象组合。
典型场景:文件系统(文件和文件夹都有 getSize())。
3.7 享元模式(Flyweight)
共享细粒度对象,减少内存占用。
典型场景:
- 围棋棋子:只有黑白两色,坐标由外部传入
- Java 字符串常量池
- 线程池、连接池
4 · 行为型模式
4.1 观察者模式(Observer)
一对多依赖:主题状态变化时通知所有观察者。
interface Observer {
void update(String msg);
}
class Subject {
private List<Observer> observers = new ArrayList<>();
void attach(Observer o) { observers.add(o); }
void notify(String msg) {
for (Observer o : observers) o.update(msg);
}
}
应用:事件总线、消息订阅、MVVM 数据绑定、消息队列。

4.2 策略模式(Strategy)
把算法族分别封装,让算法可以互相替换。
interface DiscountStrategy {
double applyDiscount(double price);
}
class NormalDiscount implements DiscountStrategy {
public double applyDiscount(double price) { return price; }
}
class VipDiscount implements DiscountStrategy {
public double applyDiscount(double price) { return price * 0.8; }
}
配合简单工厂,可以消除大量 if-else。
4.3 模板方法(Template Method)
父类定义流程骨架,子类实现具体步骤。
abstract class Game {
final void play() { init(); start(); end(); }
abstract void init();
abstract void start();
abstract void end();
}
4.4 责任链模式(Chain of Responsibility)
请求沿链传递,每个节点决定处理或传递。
应用:中间件管道(Express、Koa)、审批流程、异常处理链。
4.5 命令模式(Command)
把请求封装成对象,支持撤销/重做、日志、队列。
应用:编辑器撤销/重做、线程池任务、遥控器按钮。
4.6 状态模式(State)
对象行为随状态改变。
例如自动售货机:空闲 → 投币 → 选择商品 → 出货 → 空闲。
4.7 迭代器模式(Iterator)
提供统一遍历接口,隐藏底层实现。
Java Iterator、C++ std::iterator。
4.8 中介者模式(Mediator)
集中管理多个对象之间的交互。
应用:聊天室(所有人发消息给聊天室,由聊天室转发)。
4.9 备忘录模式(Memento)
保存对象状态,支持恢复。
应用:游戏存档、编辑器历史状态。
4.10 访问者模式(Visitor)
在不修改类的前提下,为类添加新操作。
应用:AST 遍历、编译器 Visitor 模式。
5 · 架构分层
5.1 MVC
- Model:数据和业务逻辑
- View:界面展示
- Controller:接收输入、调用 Model、更新 View
缺点:Controller 容易臃肿。
5.2 MVP
Presenter 替代 Controller,View 通过接口与 Presenter 交互。
适合:Android、Qt 客户端开发。
5.3 MVVM
ViewModel 通过数据绑定自动同步 View。
适合:Vue、Angular、WPF。
5.4 分层架构原则
- 依赖方向:上层依赖下层
- 同层之间不直接依赖
- 通过接口防腐(Anti-Corruption Layer)
- 避免跨层调用和环形依赖
6 · DDD 领域驱动设计
6.1 核心概念
- 领域(Domain):业务问题空间
- 限界上下文(Bounded Context):一个模型适用的边界
- 聚合根(Aggregate Root):一致性边界,外部只能通过聚合根修改内部对象
- 实体(Entity):有唯一标识,状态可变
- 值对象(Value Object):无身份,不可变
- 领域事件(Domain Event):用事件表达业务发生的事情
6.2 分层架构
接口层(Controller / API)
↓
应用层(Application Service,编排领域对象)
↓
领域层(Domain,核心业务逻辑)
↓
基础设施层(Repository / Message / RPC 实现)
6.3 什么时候用 DDD
- 业务复杂、规则多
- 团队规模大,需要统一语言
- 不适合简单 CRUD 系统
7 · 微服务架构
7.1 单体 vs 微服务
| 特性 |
单体 |
微服务 |
| 部署 |
一起部署 |
独立部署 |
| 扩展 |
整体扩 |
按服务扩 |
| 技术栈 |
统一 |
可异构 |
| 故障隔离 |
差 |
好 |
| 复杂度 |
低 |
高 |
| 数据一致性 |
容易 |
困难 |
7.2 微服务拆分原则
- 按业务能力拆分,不按技术层拆分
- 服务之间有清晰的边界和责任
- 每个服务独立数据库
- 避免分布式单体(只是把代码拆成多个 jar,还是一起部署)
7.3 关键组件
- API 网关:统一入口、路由、鉴权、限流
- 服务注册与发现:Consul、Nacos、Eureka
- 配置中心:Apollo、Nacos、Spring Cloud Config
- 服务通信:REST、gRPC、消息队列
- 链路追踪:Jaeger、SkyWalking、Zipkin
- 日志与监控:ELK、Prometheus + Grafana
7.4 分布式事务
- 两阶段提交(2PC):强一致,性能差
- TCC(Try-Confirm-Cancel):业务补偿
- Saga:长事务,按正向/逆向流程执行
- 本地消息表:最终一致,适合异步场景
7.5 微服务不是银弹
如果你的团队小于 10 人、业务不复杂,单体 + 模块化可能更合适。微服务带来的是运维复杂度的提升。