设计模式全景图:六大原则、23 种 GoF 模式与 J2EE 模式
- 约 16 分钟读完 - 全文 6125 字设计模式全景图:六大原则、23 种 GoF 模式与 J2EE 模式
设计模式是面向对象设计中反复出现问题的可复用解决方案。掌握它们能够帮助我们写出更易扩展、更易维护、更清晰的代码。本文从六大设计原则出发,完整梳理 GoF 23 种设计模式以及 8 种 J2EE 模式,并配合类图、意图说明和 JDK/Spring 中的典型应用,帮助建立系统性的知识地图。
一、设计模式的六大原则
1. 开闭原则(Open Close Principle)
对扩展开放,对修改关闭。
当程序需要新增功能时,应通过增加新代码实现,而不是修改已有代码。核心手段是抽象化:使用接口和抽象类。
graph LR
A[业务调用方] --> B[抽象接口]
B --> C[旧实现]
B --> D[新实现]
style D fill:#e1f5e1
2. 里氏代换原则(Liskov Substitution Principle)
任何基类可以出现的地方,子类一定可以出现。子类替换基类后,程序功能不应受影响。
classDiagram
class Animal { +eat() }
class Dog { +eat() }
class Cat { +eat() }
Animal <|-- Dog
Animal <|-- Cat
3. 依赖倒转原则(Dependence Inversion Principle)
高层模块和低层模块都应依赖抽象;要针对接口编程,而不是针对实现编程。
4. 接口隔离原则(Interface Segregation Principle)
使用多个职责单一的接口,优于使用一个庞大臃肿的接口,降低类之间的耦合。
graph TD
A[大接口] -->|拆分为| B[接口A]
A -->|拆分为| C[接口B]
A -->|拆分为| D[接口C]
B --> E[实现类1]
C --> F[实现类2]
D --> G[实现类3]
5. 迪米特法则 / 最少知道原则(Demeter Principle)
一个实体应尽量少地与其他实体发生直接交互,降低模块耦合,提高独立性。
6. 合成复用原则(Composite Reuse Principle)
优先使用组合/聚合来复用功能,而不是继承。组合更灵活,耦合更低。
classDiagram
class Car { -Engine engine; +run() }
class Engine { +start() }
Car *-- Engine : 组合
二、设计模式分类概览
设计模式通常分为三大类:创建型、结构型、行为型。J2EE 模式则专注于企业应用和表示层。
mindmap
root((设计模式))
创建型模式 5种
工厂模式
抽象工厂模式
单例模式
建造者模式
原型模式
结构型模式 8种
适配器模式
桥接模式
过滤器/标准模式
组合模式
装饰器模式
外观模式
享元模式
代理模式
行为型模式 13种
责任链模式
命令模式
解释器模式
迭代器模式
中介者模式
备忘录模式
观察者模式
状态模式
空对象模式
策略模式
模板模式
访问者模式
J2EE模式 8种
MVC模式
业务代表模式
组合实体模式
数据访问对象模式
前端控制器模式
拦截过滤器模式
服务定位器模式
传输对象模式
三、创建型模式(Creational Patterns)
创建型模式关注对象的创建过程,隐藏创建逻辑,使程序在判断需要创建哪些对象时更灵活。
1. 工厂模式(Factory Pattern)
定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使类的实例化延迟到子类。
classDiagram
class Product { <<interface>> +use() }
class ConcreteProductA { +use() }
class ConcreteProductB { +use() }
class Creator { +factoryMethod() Product }
class ConcreteCreatorA { +factoryMethod() Product }
class ConcreteCreatorB { +factoryMethod() Product }
Product <|.. ConcreteProductA
Product <|.. ConcreteProductB
Creator <|-- ConcreteCreatorA
Creator <|-- ConcreteCreatorB
Creator ..> Product
ConcreteCreatorA ..> ConcreteProductA
ConcreteCreatorB ..> ConcreteProductB
JDK 应用: java.text.DateFormat.getDateInstance()、KeyGenerator.getInstance()。
2. 抽象工厂模式(Abstract Factory Pattern)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
classDiagram
class AbstractFactory { <<interface>> +createProductA() +createProductB() }
class ConcreteFactory1 { +createProductA() +createProductB() }
class ConcreteFactory2 { +createProductA() +createProductB() }
class AbstractProductA
class AbstractProductB
AbstractFactory <|.. ConcreteFactory1
AbstractFactory <|.. ConcreteFactory2
ConcreteFactory1 ..> AbstractProductA
ConcreteFactory1 ..> AbstractProductB
ConcreteFactory2 ..> AbstractProductA
ConcreteFactory2 ..> AbstractProductB
3. 单例模式(Singleton Pattern)
确保一个类只有一个实例,并提供一个全局访问点。
classDiagram
class Singleton {
-static Singleton instance
-Singleton()
+static getInstance() Singleton
}
JDK 应用: Runtime.getRuntime()。Spring 应用: 默认 Bean 作用域为单例。
4. 建造者模式(Builder Pattern)
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
classDiagram
class Product { +partA +partB +partC }
class Builder { <<interface>> +buildPartA() +buildPartB() +getResult() }
class ConcreteBuilder { +buildPartA() +buildPartB() +getResult() }
class Director { +construct(builder) }
Builder <|.. ConcreteBuilder
ConcreteBuilder ..> Product
Director ..> Builder
5. 原型模式(Prototype Pattern)
通过复制现有对象来创建新对象,而不是新建实例。适用于创建成本较高的对象。
classDiagram
class Prototype { <<interface>> +clone() }
class ConcretePrototype { +clone() }
Prototype <|.. ConcretePrototype
JDK 应用: Object.clone()、Cloneable 接口。
四、结构型模式(Structural Patterns)
结构型模式关注对象之间的组合和关系,解决如何构建灵活且可复用的类和对象结构。
1. 适配器模式(Adapter Pattern)
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。
classDiagram
class Target { <<interface>> +request() }
class Adapter { +request() }
class Adaptee { +specificRequest() }
Target <|.. Adapter
Adapter --> Adaptee
JDK 应用: Arrays.asList()、InputStreamReader。
2. 桥接模式(Bridge Pattern)
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
classDiagram
class Abstraction { -Implementor impl +operation() }
class RefinedAbstraction { +operation() }
class Implementor { <<interface>> +operationImpl() }
class ConcreteImplementorA { +operationImpl() }
class ConcreteImplementorB { +operationImpl() }
Abstraction <|-- RefinedAbstraction
Abstraction o-- Implementor
Implementor <|.. ConcreteImplementorA
Implementor <|.. ConcreteImplementorB
3. 过滤器模式 / 标准模式(Filter / Criteria Pattern)
使用不同的标准来过滤一组对象,并通过逻辑运算以解耦的方式把它们连接起来。常用于集合筛选。
classDiagram
class Criteria { <<interface>> +meetCriteria(list) }
class CriteriaMale { +meetCriteria(list) }
class CriteriaFemale { +meetCriteria(list) }
class AndCriteria { +meetCriteria(list) }
class OrCriteria { +meetCriteria(list) }
Criteria <|.. CriteriaMale
Criteria <|.. CriteriaFemale
Criteria <|.. AndCriteria
Criteria <|.. OrCriteria
AndCriteria --> Criteria
OrCriteria --> Criteria
4. 组合模式(Composite Pattern)
将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
classDiagram
class Component { +operation() }
class Leaf { +operation() }
class Composite { -children +add() +remove() +operation() }
Component <|-- Leaf
Component <|-- Composite
Composite o-- Component
JDK 应用: java.awt.Container 与 Component。
5. 装饰器模式(Decorator Pattern)
动态地给一个对象添加一些额外的职责,比生成子类更灵活。
classDiagram
class Component { <<interface>> +operation() }
class ConcreteComponent { +operation() }
class Decorator { -Component component +operation() }
class ConcreteDecoratorA { +operation() }
class ConcreteDecoratorB { +operation() }
Component <|.. ConcreteComponent
Component <|.. Decorator
Decorator <|-- ConcreteDecoratorA
Decorator <|-- ConcreteDecoratorB
Decorator o-- Component
JDK 应用: Java IO 流 BufferedInputStream、DataInputStream、ZipOutputStream。
6. 外观模式(Facade Pattern)
为子系统中的一组接口提供一个一致的入口,定义了一个高层接口,使子系统更容易使用。
classDiagram
class Facade { +simplifiedOperation() }
class SubSystemA { +operationA() }
class SubSystemB { +operationB() }
class SubSystemC { +operationC() }
Facade --> SubSystemA
Facade --> SubSystemB
Facade --> SubSystemC
7. 享元模式(Flyweight Pattern)
运用共享技术有效地支持大量细粒度对象,减少内存占用。
classDiagram
class FlyweightFactory { -pool +getFlyweight(key) }
class Flyweight { <<interface>> +operation() }
class ConcreteFlyweight { +operation() }
FlyweightFactory o-- Flyweight
Flyweight <|.. ConcreteFlyweight
JDK 应用: Integer.valueOf() 缓存(-128-127)、String 常量池。
8. 代理模式(Proxy Pattern)
为其他对象提供一种代理以控制对这个对象的访问。
classDiagram
class Subject { <<interface>> +request() }
class RealSubject { +request() }
class Proxy { -RealSubject real +request() }
Subject <|.. RealSubject
Subject <|.. Proxy
Proxy --> RealSubject
JDK 应用: JDK 动态代理 Proxy.newProxyInstance()。Spring 应用: AOP 使用 JDK 动态代理和 CGLIB。
五、行为型模式(Behavioral Patterns)
行为型模式关注对象之间的通信和交互,解决对象之间的责任分配和算法封装。
1. 责任链模式(Chain of Responsibility Pattern)
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求。
classDiagram
class Handler { <<interface>> +setNext(handler) +handle(request) }
class ConcreteHandlerA { +handle(request) }
class ConcreteHandlerB { +handle(request) }
Handler <|.. ConcreteHandlerA
Handler <|.. ConcreteHandlerB
Handler --> Handler : next
2. 命令模式(Command Pattern)
将请求封装为对象,从而可以用不同的请求、队列或日志来参数化其他对象,同时支持可撤销操作。
classDiagram
class Command { <<interface>> +execute() }
class ConcreteCommand { -receiver +execute() }
class Invoker { -command +setCommand() +invoke() }
class Receiver { +action() }
Command <|.. ConcreteCommand
Invoker --> Command
ConcreteCommand --> Receiver
3. 解释器模式(Interpreter Pattern)
给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
classDiagram
class AbstractExpression { +interpret(context) }
class TerminalExpression { +interpret(context) }
class NonterminalExpression { +interpret(context) }
AbstractExpression <|-- TerminalExpression
AbstractExpression <|-- NonterminalExpression
NonterminalExpression o-- AbstractExpression
JDK 应用: Java 正则表达式 Pattern 与 Matcher。
4. 迭代器模式(Iterator Pattern)
提供一种方法顺序访问一个聚合对象中的各个元素,而又无需暴露该对象的内部表示。
classDiagram
class Iterator { <<interface>> +hasNext() +next() }
class ConcreteIterator { +hasNext() +next() }
class Aggregate { <<interface>> +createIterator() }
class ConcreteAggregate { +createIterator() }
Iterator <|.. ConcreteIterator
Aggregate <|.. ConcreteAggregate
ConcreteAggregate ..> ConcreteIterator
JDK 应用: java.util.Iterator、java.util.Enumeration。
5. 中介者模式(Mediator Pattern)
用一个中介对象来封装一系列对象交互,使对象不需要显式地相互引用,从而使其耦合松散。
classDiagram
class Mediator { <<interface>> +send(message, colleague) }
class ConcreteMediator { +send(message, colleague) }
class Colleague { -Mediator mediator }
class ConcreteColleagueA
class ConcreteColleagueB
Mediator <|.. ConcreteMediator
Colleague <|-- ConcreteColleagueA
Colleague <|-- ConcreteColleagueB
Colleague --> Mediator
ConcreteMediator --> ConcreteColleagueA
ConcreteMediator --> ConcreteColleagueB
6. 备忘录模式(Memento Pattern)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后恢复。
classDiagram
class Originator { +createMemento() +restore(memento) }
class Memento { -state }
class Caretaker { -mementos }
Originator ..> Memento
Caretaker o-- Memento
7. 观察者模式(Observer Pattern)
定义对象间的一对多依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
classDiagram
class Subject { <<interface>> +registerObserver() +removeObserver() +notifyObservers() }
class ConcreteSubject { -state +notifyObservers() }
class Observer { <<interface>> +update() }
class ConcreteObserverA { +update() }
class ConcreteObserverB { +update() }
Subject <|.. ConcreteSubject
Observer <|.. ConcreteObserverA
Observer <|.. ConcreteObserverB
ConcreteSubject --> Observer
JDK 应用: java.util.Observer(已弃用)和 Observable。Spring 应用: Spring 事件驱动模型 ApplicationEvent、ApplicationListener。
8. 状态模式(State Pattern)
允许对象在其内部状态改变时改变它的行为,对象看起来好像修改了它的类。
classDiagram
class Context { -State state +request() }
class State { <<interface>> +handle() }
class ConcreteStateA { +handle() }
class ConcreteStateB { +handle() }
Context o-- State
State <|.. ConcreteStateA
State <|.. ConcreteStateB
9. 空对象模式(Null Object Pattern)
用一个空对象取代 null 检查,提供默认的"什么也不做"的行为,避免空指针异常。
classDiagram
class Animal { <<interface>> +makeSound() }
class Dog { +makeSound() }
class NullAnimal { +makeSound() }
Animal <|.. Dog
Animal <|.. NullAnimal
10. 策略模式(Strategy Pattern)
定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。
classDiagram
class Strategy { <<interface>> +execute() }
class ConcreteStrategyA { +execute() }
class ConcreteStrategyB { +execute() }
class Context { -Strategy strategy +setStrategy() +executeStrategy() }
Strategy <|.. ConcreteStrategyA
Strategy <|.. ConcreteStrategyB
Context o-- Strategy
JDK 应用: Comparator 接口与 Collections.sort()。
11. 模板模式(Template Pattern)
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变算法结构即可重定义该算法的某些特定步骤。
classDiagram
class AbstractClass { +templateMethod() +primitiveOperation() }
class ConcreteClass { +primitiveOperation() }
AbstractClass <|-- ConcreteClass
JDK 应用: Arrays.sort() 配合 Comparable。Spring 应用: RestTemplate、JmsTemplate、JpaTemplate。
12. 访问者模式(Visitor Pattern)
表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
classDiagram
class Element { <<interface>> +accept(visitor) }
class ConcreteElementA { +accept(visitor) }
class ConcreteElementB { +accept(visitor) }
class Visitor { <<interface>> +visitA() +visitB() }
class ConcreteVisitor { +visitA() +visitB() }
Element <|.. ConcreteElementA
Element <|.. ConcreteElementB
Visitor <|.. ConcreteVisitor
ConcreteElementA ..> Visitor
ConcreteElementB ..> Visitor
六、J2EE 模式
J2EE 模式专注于企业应用,尤其是表示层和业务层的架构设计。这些模式由 Sun Java Center 鉴定。
1. MVC 模式(MVC Pattern)
将应用程序分为 Model(模型)、View(视图)、Controller(控制器)三层,实现关注点分离。
graph LR
V[View] --> C[Controller]
C --> M[Model]
M --> V
Spring 应用: Spring MVC 是典型实现。
2. 业务代表模式(Business Delegate Pattern)
为表示层提供对业务服务的访问抽象,减少表示层与业务层之间的耦合。
graph LR
A[Client/Controller] --> B[Business Delegate]
B --> C[Business Service]
C --> D[DAO/数据层]
3. 组合实体模式(Composite Entity Pattern)
将一组相关的持久化对象组合成一个粗粒度实体,减少网络调用次数,提高性能。
classDiagram
class CompositeEntity { -DependentObjectA a -DependentObjectB b +getData() }
class DependentObjectA
class DependentObjectB
CompositeEntity *-- DependentObjectA
CompositeEntity *-- DependentObjectB
4. 数据访问对象模式(Data Access Object Pattern)
将底层数据访问逻辑与高层业务逻辑分离,提供一个统一的接口访问数据库。
graph LR
A[Business Object] --> B[DAO Interface]
B --> C[DAO Implementation]
C --> D[Data Source/Database]
Spring 应用: Spring Data JPA、MyBatis Mapper 都是 DAO 模式的具体实现。
5. 前端控制器模式(Front Controller Pattern)
提供一个集中的入口点来处理所有请求,通常负责认证、日志、路由等横切关注点。
graph LR
A[所有请求] --> B[Front Controller]
B --> C[Dispatcher]
C --> D[具体 Handler]
Spring 应用: DispatcherServlet 是前端控制器模式的实现。
6. 拦截过滤器模式(Intercepting Filter Pattern)
在请求到达目标处理器之前,通过一系列过滤器链对请求进行预处理(如编码、认证、日志)。
graph LR
A[Request] --> F1[Filter 1]
F1 --> F2[Filter 2]
F2 --> F3[Filter N]
F3 --> T[Target]
T --> F3
F3 --> F2
F2 --> F1
F1 --> R[Response]
Spring 应用: Spring 的 HandlerInterceptor、Servlet Filter。
7. 服务定位器模式(Service Locator Pattern)
提供一个中心化的注册表,用于获取服务实例,减少服务依赖的直接查找。
classDiagram
class ServiceLocator { +getService(name) }
class Cache { -services }
class InitialContext { +lookup(name) }
class Service { <<interface>> +execute() }
ServiceLocator --> Cache
ServiceLocator --> InitialContext
ServiceLocator ..> Service
8. 传输对象模式(Transfer Object Pattern)
通过简单的 POJO 对象在不同层之间传输数据,减少远程调用的网络开销,也称为 DTO(Data Transfer Object)。
classDiagram
class UserDTO { -id -name -email +getters/setters }
class UserService { +getUserDTO(id) }
class UserController { +showUser(dto) }
UserService ..> UserDTO
UserController ..> UserDTO
七、JDK、Java IO 与 Spring 中的模式速查
| 模式 | JDK 示例 | Spring 示例 |
|---|---|---|
| 工厂模式 | DateFormat.getDateInstance()、KeyGenerator.getInstance() |
BeanFactory |
| 单例模式 | Runtime.getRuntime() |
默认 Bean 作用域 |
| 原型模式 | Object.clone()、Cloneable |
@Scope("prototype") |
| 适配器模式 | Arrays.asList()、InputStreamReader |
MVC 的 Controller 适配器 |
| 装饰器模式 | BufferedInputStream、ZipOutputStream |
- |
| 代理模式 | JDK 动态代理 | AOP |
| 组合模式 | java.awt.Container / Component |
- |
| 享元模式 | Integer.valueOf()、String 常量池 |
- |
| 模板方法模式 | Arrays.sort() + Comparable |
RestTemplate、JpaTemplate |
| 策略模式 | Comparator、Collections.sort() |
ResourceLoader 策略 |
| 观察者模式 | Observer / Observable |
Spring 事件驱动模型 |
| 解释器模式 | Pattern / Matcher |
SpEL 表达式 |
| 责任链模式 | Servlet Filter Chain | HandlerInterceptor 链 |
| MVC 模式 | - | Spring MVC |
| DAO 模式 | JDBC Template | Spring Data JPA / MyBatis |
| 前端控制器 | - | DispatcherServlet |
Java IO 中使用的模式
Java IO 同时使用了适配器模式和装饰器模式:
- 适配器模式:
InputStreamReader将InputStream字节流适配为Reader字符流。 - 装饰器模式:
BufferedInputStream、DataInputStream、ZipOutputStream等通过包装InputStream动态增强功能。
// 装饰器模式:逐层包装
InputStream fis = new FileInputStream("file.txt");
InputStream bis = new BufferedInputStream(fis); // 增加缓冲
DataInputStream dis = new DataInputStream(bis); // 增加基本类型读取
// 适配器模式:字节流转字符流
Reader reader = new InputStreamReader(fis, StandardCharsets.UTF_8);八、如何选择设计模式
设计模式不是越复杂越好。选择时可以从以下角度思考:
- 问题类型:是对象创建、结构组织,还是行为交互?
- 变化方向:系统中哪些部分经常变化?把变化的部分封装起来。
- 开闭原则:新增功能时是否能不修改已有代码?
- 复杂度收益:不要为了用模式而增加不必要的抽象。
一张简化的决策地图:
flowchart TD
A[遇到设计问题] --> B{对象创建复杂?}
B -->|是| C[创建型模式]
B -->|否| D{对象结构复杂?}
D -->|是| E[结构型模式]
D -->|否| F{对象交互复杂?}
F -->|是| G[行为型模式]
F -->|否| H[保持简单,遵循原则]
总结
设计模式是前人总结的设计经验,核心目标是让软件更易扩展、更易维护、更易理解。掌握它们的关键不是背诵每个类图,而是:
- 理解六大原则,它们是选择模式的判断依据;
- 熟悉 23 种 GoF 模式和 J2EE 模式的适用场景;
- 多读优秀源码(JDK、Spring),在真实代码中感受模式的应用;
- 避免过度设计,合适才是最好的。
从 BeanFactory 到 DispatcherServlet,从 Java IO 的装饰器到 Spring AOP 的代理,设计模式无处不在。理解这些模式,能帮助我们在面对复杂系统时做出更清晰的结构选择。
参考:
- 菜鸟教程 - 设计模式
- dailyprogrammer - JDK 类库常用的设计模式
- Design Patterns: Elements of Reusable Object-Oriented Software (GoF)