前言
设计模式是软件工程中反复验证的解决方案模板。对于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 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 { private final String method; private final String url; 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中的Builder :UriComponentsBuilder、MockMvcRequestBuilders、WebClient.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) { return data; } private String decrypt (String data) { 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) { return data; } private String decompress (String data) { 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 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) { if (!inventory.checkStock(request.getProductId(), request.getQuantity())) { return OrderResult.fail("Out of stock" ); } if (!payment.charge(request.getUserId(), request.getTotalAmount())) { return OrderResult.fail("Payment failed" ); } String trackingNo = shipping.dispatch(request); 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
接口的不同实现(ClassPathResource、FileSystemResource、UrlResource)就是策略模式的体现。
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 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; } }@Component public class EmailNotificationListener { @EventListener public void onOrderCreated (OrderCreatedEvent event) { emailService.sendOrderConfirmation(event.getOrder()); } }@Component public class InventoryListener { @EventListener public void onOrderCreated (OrderCreatedEvent event) { inventoryService.deductStock(event.getOrder().getItems()); } }@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) { } }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) { 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中的模板方法 :AbstractList、AbstractMap
等抽象集合类;HttpServlet 的
doGet()、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
优先组合而非继承
最佳实践
不要为了用模式而用模式 。如果简单的
if-else 能解决问题,不需要引入策略模式。
优先使用组合而非继承 。装饰器、策略等基于组合的模式比基于继承的模式更灵活。
结合函数式编程 。Java
8+的Lambda表达式可以简化很多模式的实现,如策略模式、观察者模式。
理解框架中的模式 。学习Spring源码时关注其设计模式的运用,这是最好的实战教材。
从重构中提炼模式 。先写出能工作的代码,再通过重构引入合适的模式来改善结构。
总结
设计模式是面向对象编程的精髓,但它们不是银弹。关键在于理解每个模式解决的核心问题:
创建型模式 解决”如何创建对象”的问题
结构型模式 解决”如何组合类和对象”的问题
行为型模式 解决”对象之间如何通信”的问题
在日常开发中,建议从Spring和JDK源码中学习设计模式的实际运用,这比单纯记忆UML图更有价值。真正掌握设计模式的标志不是”能写出某个模式的代码”,而是”能在合适的场景自然地想到使用某个模式”。