Java · #java#design-patterns#oop

Java设计模式实战:23种模式在项目中的应用

2025.03.19 Java 11 min 4.3k
// 目录 · contents

前言

设计模式是软件工程中反复验证的解决方案模板。对于Java开发者而言,理解设计模式不仅能写出更优雅的代码,更能深入理解Spring、JDK等框架的设计哲学。本文将从创建型、结构型、行为型三大类别出发,结合真实项目场景,逐一剖析最常用的设计模式。

设计模式全局视图

graph TB
    DP[设计模式 23种]
    DP --> C[创建型 5种]
    DP --> S[结构型 7种]
    DP --> B[行为型 11种]

    C --> C1[Singleton 单例]
    C --> C2[Factory Method 工厂方法]
    C --> C3[Abstract Factory 抽象工厂]
    C --> C4[Builder 建造者]
    C --> C5[Prototype 原型]

    S --> S1[Adapter 适配器]
    S --> S2[Decorator 装饰器]
    S --> S3[Proxy 代理]
    S --> S4[Facade 外观]
    S --> S5[Bridge 桥接]
    S --> S6[Composite 组合]
    S --> S7[Flyweight 享元]

    B --> B1[Strategy 策略]
    B --> B2[Observer 观察者]
    B --> B3[Template Method 模板方法]
    B --> B4[Chain of Responsibility 责任链]
    B --> B5[Command / State / Iterator / ...]

    style DP fill:#f9f,stroke:#333,stroke-width:2px
    style C fill:#bbf,stroke:#333
    style S fill:#bfb,stroke:#333
    style B fill:#fbf,stroke:#333

一、创建型模式

创建型模式关注对象的创建过程,将对象的创建与使用分离,降低系统耦合度。

1.1 Singleton 单例模式

单例模式确保一个类只有一个实例,并提供全局访问点。在JDK中,Runtime.getRuntime() 就是经典的单例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 推荐方式:静态内部类实现单例
* 利用JVM类加载机制保证线程安全,同时实现懒加载
*/
public class DatabaseConnectionPool {

private DatabaseConnectionPool() {
// 初始化连接池
}

// 静态内部类在首次引用时才会被加载
private static class Holder {
private static final DatabaseConnectionPool INSTANCE =
new DatabaseConnectionPool();
}

public static DatabaseConnectionPool getInstance() {
return Holder.INSTANCE;
}

// 防止反序列化破坏单例
private Object readResolve() {
return Holder.INSTANCE;
}
}

枚举单例是Effective Java推荐的写法,天然防反射和反序列化攻击:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public enum ConfigManager {
INSTANCE;

private final Properties config = new Properties();

ConfigManager() {
try (InputStream is = getClass().getResourceAsStream("/app.properties")) {
config.load(is);
} catch (IOException e) {
throw new RuntimeException("Failed to load config", e);
}
}

public String get(String key) {
return config.getProperty(key);
}
}

Spring中的单例:Spring容器中的Bean默认就是单例的,但它不是通过私有构造器实现,而是通过容器管理(SingletonBeanRegistry)。

1.2 Factory Method 工厂方法模式

定义创建对象的接口,由子类决定实例化哪个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 抽象产品
public interface MessageSender {
void send(String message, String target);
}

// 具体产品
public class EmailSender implements MessageSender {
@Override
public void send(String message, String target) {
System.out.println("Sending email to " + target + ": " + message);
}
}

public class SmsSender implements MessageSender {
@Override
public void send(String message, String target) {
System.out.println("Sending SMS to " + target + ": " + message);
}
}

// 工厂方法
public class MessageSenderFactory {

public static MessageSender create(String type) {
return switch (type.toLowerCase()) {
case "email" -> new EmailSender();
case "sms" -> new SmsSender();
default -> throw new IllegalArgumentException("Unknown type: " + type);
};
}
}

JDK中的工厂方法Calendar.getInstance()NumberFormat.getInstance()Collection.of() 等均为工厂方法的典型应用。

1.3 Builder 建造者模式

将复杂对象的构建过程与表示分离,适用于参数众多的场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class HttpRequest {
private final String method;
private final String url;
private final Map<String, String> headers;
private final String body;
private final int timeout;

private HttpRequest(Builder builder) {
this.method = builder.method;
this.url = builder.url;
this.headers = Collections.unmodifiableMap(builder.headers);
this.body = builder.body;
this.timeout = builder.timeout;
}

public static class Builder {
// Required parameters
private final String method;
private final String url;

// Optional parameters with defaults
private Map<String, String> headers = new HashMap<>();
private String body = "";
private int timeout = 30_000;

public Builder(String method, String url) {
this.method = method;
this.url = url;
}

public Builder header(String key, String value) {
this.headers.put(key, value);
return this;
}

public Builder body(String body) {
this.body = body;
return this;
}

public Builder timeout(int timeout) {
this.timeout = timeout;
return this;
}

public HttpRequest build() {
return new HttpRequest(this);
}
}
}

// 使用示例
HttpRequest request = new HttpRequest.Builder("POST", "https://api.example.com/users")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer token123")
.body("{\"name\":\"John\"}")
.timeout(5000)
.build();

Spring中的BuilderUriComponentsBuilderMockMvcRequestBuildersWebClient.builder() 都采用了Builder模式。

1.4 Prototype 原型模式

通过复制现有对象来创建新对象,避免重复的初始化开销。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ReportTemplate implements Cloneable {
private String title;
private List<String> sections;
private Map<String, Object> metadata;

@Override
public ReportTemplate clone() {
try {
ReportTemplate copy = (ReportTemplate) super.clone();
// 深拷贝可变字段
copy.sections = new ArrayList<>(this.sections);
copy.metadata = new HashMap<>(this.metadata);
return copy;
} catch (CloneNotSupportedException e) {
throw new AssertionError("Clone not supported", e);
}
}
}

二、结构型模式

结构型模式关注类和对象的组合,通过组合获得更强大的功能。

graph LR
    A[客户端] -->|调用| B[Adapter]
    B -->|转换接口| C[被适配者]

    D[客户端] -->|调用| E[Decorator]
    E -->|增强功能| F[被装饰对象]

    G[客户端] -->|调用| H[Proxy]
    H -->|控制访问| I[真实对象]

    J[客户端] -->|调用| K[Facade]
    K -->|简化接口| L[子系统A]
    K --> M[子系统B]
    K --> N[子系统C]

2.1 Adapter 适配器模式

将一个类的接口转换成客户端期望的另一个接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 旧系统的支付接口
public class LegacyPaymentService {
public boolean processPayment(String accountId, double amount) {
System.out.println("Legacy payment: " + accountId + " -> " + amount);
return true;
}
}

// 新系统期望的接口
public interface PaymentGateway {
PaymentResult pay(PaymentRequest request);
}

// 适配器:将旧接口适配到新接口
public class LegacyPaymentAdapter implements PaymentGateway {

private final LegacyPaymentService legacyService;

public LegacyPaymentAdapter(LegacyPaymentService legacyService) {
this.legacyService = legacyService;
}

@Override
public PaymentResult pay(PaymentRequest request) {
boolean success = legacyService.processPayment(
request.getAccountId(),
request.getAmount().doubleValue()
);
return new PaymentResult(success, success ? "OK" : "FAILED");
}
}

JDK中的适配器Arrays.asList() 将数组适配为List;InputStreamReader 将字节流适配为字符流。

2.2 Decorator 装饰器模式

动态地给对象添加额外的职责,比继承更灵活。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 基础接口
public interface DataSource {
void writeData(String data);
String readData();
}

// 具体组件
public class FileDataSource implements DataSource {
private final String filename;

public FileDataSource(String filename) {
this.filename = filename;
}

@Override
public void writeData(String data) { /* 写入文件 */ }

@Override
public String readData() { /* 读取文件 */ return ""; }
}

// 装饰器基类
public abstract class DataSourceDecorator implements DataSource {
protected final DataSource wrapped;

public DataSourceDecorator(DataSource source) {
this.wrapped = source;
}
}

// 加密装饰器
public class EncryptionDecorator extends DataSourceDecorator {

public EncryptionDecorator(DataSource source) {
super(source);
}

@Override
public void writeData(String data) {
String encrypted = encrypt(data);
wrapped.writeData(encrypted);
}

@Override
public String readData() {
return decrypt(wrapped.readData());
}

private String encrypt(String data) { /* AES加密逻辑 */ return data; }
private String decrypt(String data) { /* AES解密逻辑 */ return data; }
}

// 压缩装饰器
public class CompressionDecorator extends DataSourceDecorator {

public CompressionDecorator(DataSource source) {
super(source);
}

@Override
public void writeData(String data) {
String compressed = compress(data);
wrapped.writeData(compressed);
}

@Override
public String readData() {
return decompress(wrapped.readData());
}

private String compress(String data) { /* GZIP压缩 */ return data; }
private String decompress(String data) { /* GZIP解压 */ return data; }
}

// 组合使用:先压缩再加密
DataSource source = new EncryptionDecorator(
new CompressionDecorator(
new FileDataSource("data.txt")
)
);
source.writeData("sensitive data");

JDK中的装饰器:Java I/O体系就是装饰器模式的经典案例,如 BufferedInputStream(new FileInputStream(...))

2.3 Proxy 代理模式

为其他对象提供一个代理以控制对该对象的访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// JDK动态代理实现AOP日志
public class LoggingInvocationHandler implements InvocationHandler {

private final Object target;
private static final Logger log = LoggerFactory.getLogger(LoggingInvocationHandler.class);

public LoggingInvocationHandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.nanoTime();
log.info("Invoking {} with args {}", method.getName(), Arrays.toString(args));

try {
Object result = method.invoke(target, args);
long elapsed = (System.nanoTime() - start) / 1_000_000;
log.info("{} completed in {}ms, result: {}", method.getName(), elapsed, result);
return result;
} catch (InvocationTargetException e) {
log.error("{} threw exception: {}", method.getName(), e.getCause().getMessage());
throw e.getCause();
}
}

@SuppressWarnings("unchecked")
public static <T> T createProxy(T target, Class<T> iface) {
return (T) Proxy.newProxyInstance(
iface.getClassLoader(),
new Class<?>[]{iface},
new LoggingInvocationHandler(target)
);
}
}

Spring中的代理:Spring AOP的核心就是代理模式,JDK动态代理用于接口,CGLIB代理用于类。@Transactional@Cacheable 等注解的底层实现都依赖代理。

2.4 Facade 外观模式

为子系统中的一组接口提供统一的高层接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 多个子系统
public class InventoryService { /* 库存检查 */ }
public class PaymentService { /* 支付处理 */ }
public class ShippingService { /* 物流发货 */ }
public class NotificationService { /* 通知推送 */ }

// 外观类:统一下单流程
public class OrderFacade {

private final InventoryService inventory;
private final PaymentService payment;
private final ShippingService shipping;
private final NotificationService notification;

public OrderFacade(InventoryService inventory, PaymentService payment,
ShippingService shipping, NotificationService notification) {
this.inventory = inventory;
this.payment = payment;
this.shipping = shipping;
this.notification = notification;
}

public OrderResult placeOrder(OrderRequest request) {
// 1. 检查库存
if (!inventory.checkStock(request.getProductId(), request.getQuantity())) {
return OrderResult.fail("Out of stock");
}
// 2. 扣款
if (!payment.charge(request.getUserId(), request.getTotalAmount())) {
return OrderResult.fail("Payment failed");
}
// 3. 安排发货
String trackingNo = shipping.dispatch(request);
// 4. 发送通知
notification.sendOrderConfirmation(request.getUserId(), trackingNo);

return OrderResult.success(trackingNo);
}
}

三、行为型模式

行为型模式关注对象之间的通信和职责分配。

3.1 Strategy 策略模式

定义一系列算法,将每个算法封装起来并使它们可以互换。

classDiagram
    class SortContext {
        -SortStrategy strategy
        +setStrategy(SortStrategy)
        +sort(int[]) int[]
    }

    class SortStrategy {
        <<interface>>
        +sort(int[]) int[]
    }

    class QuickSort {
        +sort(int[]) int[]
    }

    class MergeSort {
        +sort(int[]) int[]
    }

    class BubbleSort {
        +sort(int[]) int[]
    }

    SortContext --> SortStrategy
    SortStrategy <|.. QuickSort
    SortStrategy <|.. MergeSort
    SortStrategy <|.. BubbleSort
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@FunctionalInterface
public interface DiscountStrategy {
BigDecimal calculate(BigDecimal originalPrice);
}

// 各种折扣策略
public class DiscountStrategies {
public static DiscountStrategy noDiscount() {
return price -> price;
}

public static DiscountStrategy percentOff(int percent) {
BigDecimal factor = BigDecimal.valueOf(100 - percent, 2);
return price -> price.multiply(factor).setScale(2, RoundingMode.HALF_UP);
}

public static DiscountStrategy fixedAmount(BigDecimal amount) {
return price -> price.subtract(amount).max(BigDecimal.ZERO);
}

public static DiscountStrategy vipDiscount(int vipLevel) {
return switch (vipLevel) {
case 1 -> percentOff(5);
case 2 -> percentOff(10);
case 3 -> percentOff(15);
default -> noDiscount();
};
}
}

// 使用
BigDecimal finalPrice = DiscountStrategies.vipDiscount(2)
.calculate(new BigDecimal("199.00"));

Spring中的策略模式Resource 接口的不同实现(ClassPathResourceFileSystemResourceUrlResource)就是策略模式的体现。

3.2 Observer 观察者模式

定义对象间一对多的依赖关系,当一个对象状态改变时,所有依赖者都会收到通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 基于Spring事件机制的观察者模式
public class OrderCreatedEvent extends ApplicationEvent {
private final Order order;

public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
}

public Order getOrder() { return order; }
}

// 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;

@Transactional
public Order createOrder(OrderRequest request) {
Order order = orderRepository.save(buildOrder(request));
// 发布事件,解耦后续逻辑
eventPublisher.publishEvent(new OrderCreatedEvent(this, order));
return order;
}
}

// 监听器1:发送邮件
@Component
public class EmailNotificationListener {
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
emailService.sendOrderConfirmation(event.getOrder());
}
}

// 监听器2:更新库存
@Component
public class InventoryListener {
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
inventoryService.deductStock(event.getOrder().getItems());
}
}

// 监听器3:异步记录日志
@Component
public class AuditLogListener {
@Async
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
auditLogService.log("ORDER_CREATED", event.getOrder().getId());
}
}

3.3 Template Method 模板方法模式

定义操作中算法的骨架,将某些步骤延迟到子类中实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public abstract class AbstractDataExporter {

// 模板方法:定义导出的固定流程
public final void export(ExportConfig config) {
List<Map<String, Object>> data = queryData(config);
List<Map<String, Object>> processed = processData(data);
byte[] content = formatOutput(processed);
writeOutput(config.getOutputPath(), content);
afterExport(config);
}

// 子类必须实现的抽象方法
protected abstract List<Map<String, Object>> queryData(ExportConfig config);
protected abstract byte[] formatOutput(List<Map<String, Object>> data);

// 可选的钩子方法,子类可以覆盖
protected List<Map<String, Object>> processData(List<Map<String, Object>> data) {
return data; // 默认不处理
}

protected void afterExport(ExportConfig config) {
// 默认空实现
}

private void writeOutput(String path, byte[] content) {
// 写入文件的通用逻辑
}
}

// CSV导出器
public class CsvExporter extends AbstractDataExporter {
@Override
protected List<Map<String, Object>> queryData(ExportConfig config) {
return jdbcTemplate.queryForList(config.getSql());
}

@Override
protected byte[] formatOutput(List<Map<String, Object>> data) {
// 将数据格式化为CSV
StringBuilder sb = new StringBuilder();
if (!data.isEmpty()) {
sb.append(String.join(",", data.get(0).keySet())).append("\n");
for (Map<String, Object> row : data) {
sb.append(String.join(",",
row.values().stream().map(String::valueOf).toList()
)).append("\n");
}
}
return sb.toString().getBytes(StandardCharsets.UTF_8);
}
}

JDK中的模板方法AbstractListAbstractMap 等抽象集合类;HttpServletdoGet()doPost() 也是模板方法。

3.4 Chain of Responsibility 责任链模式

使多个对象都有机会处理请求,将这些对象连成一条链,沿链传递请求。

graph LR
    Request[请求] --> A[认证Filter]
    A -->|通过| B[限流Filter]
    B -->|通过| C[日志Filter]
    C -->|通过| D[业务处理]
    A -->|拒绝| R1[401 Unauthorized]
    B -->|拒绝| R2[429 Too Many Requests]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public abstract class RequestHandler {
private RequestHandler next;

public RequestHandler setNext(RequestHandler next) {
this.next = next;
return next;
}

public final Response handle(Request request) {
Response response = doHandle(request);
if (response != null) {
return response; // 当前处理器已处理,返回结果
}
if (next != null) {
return next.handle(request); // 传递给下一个处理器
}
return Response.of(400, "No handler available");
}

protected abstract Response doHandle(Request request);
}

// 认证处理器
public class AuthHandler extends RequestHandler {
@Override
protected Response doHandle(Request request) {
String token = request.getHeader("Authorization");
if (token == null || !tokenService.validate(token)) {
return Response.of(401, "Unauthorized");
}
return null; // 传递给下一个处理器
}
}

// 限流处理器
public class RateLimitHandler extends RequestHandler {
private final RateLimiter limiter = RateLimiter.create(100);

@Override
protected Response doHandle(Request request) {
if (!limiter.tryAcquire()) {
return Response.of(429, "Too Many Requests");
}
return null;
}
}

// 组装责任链
RequestHandler chain = new AuthHandler();
chain.setNext(new RateLimitHandler())
.setNext(new LoggingHandler())
.setNext(new BusinessHandler());

Response response = chain.handle(incomingRequest);

Spring中的责任链Filter Chain(Servlet规范)、Spring Security的 SecurityFilterChain、Spring MVC的 HandlerInterceptor 都是责任链模式的实际应用。

设计原则与模式选择

在使用设计模式时,应遵循以下原则:

原则 缩写 含义
单一职责 SRP 一个类只负责一件事
开闭原则 OCP 对扩展开放,对修改关闭
里氏替换 LSP 子类能替代父类使用
接口隔离 ISP 使用多个专门的接口
依赖倒置 DIP 依赖抽象而非具体实现
合成复用 CRP 优先组合而非继承

最佳实践

  1. 不要为了用模式而用模式。如果简单的 if-else 能解决问题,不需要引入策略模式。
  2. 优先使用组合而非继承。装饰器、策略等基于组合的模式比基于继承的模式更灵活。
  3. 结合函数式编程。Java 8+的Lambda表达式可以简化很多模式的实现,如策略模式、观察者模式。
  4. 理解框架中的模式。学习Spring源码时关注其设计模式的运用,这是最好的实战教材。
  5. 从重构中提炼模式。先写出能工作的代码,再通过重构引入合适的模式来改善结构。

总结

设计模式是面向对象编程的精髓,但它们不是银弹。关键在于理解每个模式解决的核心问题:

  • 创建型模式解决”如何创建对象”的问题
  • 结构型模式解决”如何组合类和对象”的问题
  • 行为型模式解决”对象之间如何通信”的问题

在日常开发中,建议从Spring和JDK源码中学习设计模式的实际运用,这比单纯记忆UML图更有价值。真正掌握设计模式的标志不是”能写出某个模式的代码”,而是”能在合适的场景自然地想到使用某个模式”。

作者 · authorzt
发布 · date2025-03-19
篇幅 · length4.3k 字 · 11 min
许可 · licenseCC BY-SA 4.0
$ echo "comments" · 评论