设计模式入门:从 GoF 分类到 SOLID 原则实战
一、设计模式的起源与核心价值
1.1 为什么需要设计模式?
在软件开发中,重复解决相似问题会导致:
-
代码冗余:相同逻辑重复实现(如日志模块)
-
维护困难:修改一处影响多处(如硬编码策略)
-
扩展性差:新增功能需大幅改动现有代码
设计模式通过可复用的解决方案模板,帮助开发者:
-
提升代码可维护性(遵循开闭原则)
-
降低模块耦合度(依赖倒置原则)
-
加速设计决策(直接应用成熟方案)
1.2 GoF 23 种模式分类
1994 年《设计模式:可复用面向对象软件的基础》提出经典分类,形成设计模式的 “瑞士军刀”:
graph TD
A[创建型模式] --> B(单例)
A --> C(工厂)
A --> D(建造者)
A --> E(原型)
F[结构型模式] --> G(代理)
F --> H(装饰器)
F --> I(适配器)
F --> J(组合)
K[行为型模式] --> L(策略)
K --> M(模板方法)
K --> N(观察者)
K --> O(责任链)
style A fill:#f9f, F fill:#b8d9a9, K fill:#a9d9d9
创建型模式(5 种)
核心目的:封装对象创建逻辑,解耦对象创建与使用。
模式 | 核心思想 | 典型场景 |
---|---|---|
工厂模式 | 通过工厂类封装对象创建,客户端无需知道具体实现类 | 日志工厂、数据库连接工厂 |
抽象工厂模式 | 提供创建一系列相关对象的接口,支持多产品族扩展 | 跨平台 UI 组件(如 Windows/Linux 按钮) |
单例模式 | 确保类仅有一个实例,提供全局访问点 | 配置管理器、日志记录器 |
建造者模式 | 分步构建复杂对象,支持链式调用和不同表示的创建 | 用户配置对象、SQL 语句拼接 |
原型模式 | 通过克隆现有对象创建新实例,避免重复初始化 | 对象缓存、快速复制大量对象 |
结构型模式(7 种)
核心目的:优化类或对象的结构,解耦复杂结构中的组件。
模式 | 核心思想 | 典型场景 |
---|---|---|
适配器模式 | 将不兼容的接口转换为客户端期望的接口 | 旧系统对接、第三方 API 适配 |
桥接模式 | 分离抽象与实现,使两者可独立扩展 | 跨平台图形渲染、驱动程序设计 |
组合模式 | 将对象组合成树形结构,统一处理单个对象和组合对象 | 文件系统、组织结构管理 |
装饰器模式 | 动态添加对象功能,避免继承导致的类爆炸 | IO 流增强(如缓冲流、加密流) |
外观模式 | 为复杂子系统提供统一简单接口 | 微服务网关、系统集成平台 |
享元模式 | 共享对象实例,减少内存占用 | 文本编辑器字符共享、数据库连接池 |
代理模式 | 通过代理对象控制对目标对象的访问 | 远程调用、权限控制、缓存代理 |
行为型模式(11 种)
核心目的:优化对象间的交互逻辑,解耦对象行为与职责。
模式 | 核心思想 | 典型场景 |
---|---|---|
策略模式 | 定义一系列算法,支持动态切换 | 支付策略(支付宝 / 微信支付) |
模板方法模式 | 定义算法骨架,具体步骤延迟到子类实现 | 订单处理流程、考试流程 |
观察者模式 | 对象间建立订阅 - 发布机制,状态变化时自动通知 | 股票行情通知、消息推送系统 |
迭代器模式 | 统一数据遍历方式,解耦遍历逻辑与数据结构 | 集合框架(如 Java Iterator) |
责任链模式 | 将请求传递给多个处理者,直至有处理者响应 | 审批流程、错误处理链 |
命令模式 | 封装操作命令,支持撤销、重做和异步执行 | 文本编辑器撤销、分布式任务调度 |
备忘录模式 | 保存和恢复对象状态,支持多版本管理 | 游戏存档、编辑器撤销功能 |
状态模式 | 对象状态变化时改变其行为,状态逻辑封装在独立类中 | 电梯状态控制、订单状态机 |
访问者模式 | 分离数据结构与操作,支持动态添加新操作 | 编译器优化、文档格式转换 |
中介者模式 | 通过中介者解耦对象间复杂交互,集中管理通信逻辑 | GUI 组件联动、微服务消息路由 |
解释器模式 | 定义语言文法,实现解释器解析和执行句子 | 正则表达式、自定义配置语言 |
二、面向对象设计五大核心原则(SOLID)
2.1 单一职责原则(SRP)
定义:一个类只负责一项职责反例:
// 反模式:同时处理用户认证和日志记录
public class UserService {
public boolean login(String username, String password) {
// 认证逻辑
log("用户登录:" + username);
return true;
}
private void log(String msg) {
// 日志写入文件
}
}
重构:
// 拆分认证服务与日志服务
public class UserAuthService { /* 认证逻辑 */ }
public class LoggerService { /* 日志写入 */ }
2.2 开闭原则(OCP)
定义:对扩展开放,对修改关闭实现方式:
-
通过接口定义行为(Logger接口)
-
具体实现类继承接口(FileLogger, ConsoleLogger)
-
客户端依赖接口而非实现
实战:
// 定义日志接口
public interface Logger {
void log(String message);
}
// 扩展实现(无需修改原有代码)
public class FileLogger implements Logger { /* 文件日志 */ }
public class ConsoleLogger implements Logger { /* 控制台日志 */ }
// 客户端注入接口(Spring依赖注入)
@Service
public class OrderService {
private final Logger logger;
public OrderService(Logger logger) { this.logger = logger; }
}
2.3 依赖倒置原则(DIP)
定义:高层模块不依赖低层模块,共同依赖抽象错误实践:
// 高层模块直接依赖具体实现(数据库操作)
public class UserRepository {
private MySQLConnection conn; // 低层模块
}
正确实践:
// 定义抽象接口
public interface DatabaseConnection { /* 数据库连接 */ }
// 具体实现(MySQL/Oracle)
public class MySQLConnection implements DatabaseConnection { /* ... */ }
// 高层模块依赖抽象
public class UserRepository {
private final DatabaseConnection conn;
public UserRepository(DatabaseConnection conn) { this.conn = conn; }
}
2.4 里氏替换原则(LSP)
定义:子类可替换父类而不影响程序逻辑案例:
// 正方形不应继承长方形(违反面积计算逻辑)
class Rectangle {
protected int width, height;
public void setWidth(int w) { width = w; }
public void setHeight(int h) { height = h; }
}
// 反模式:正方形强制要求width=height
class Square extends Rectangle {
@Override
public void setWidth(int w) {
width = w;
height = w; // 破坏里氏替换原则
}
}
2.5 接口隔离原则(ISP)
定义:客户端不依赖不需要的接口方法反模式:
// 胖接口包含无关方法
public interface Animal {
void eat();
void fly(); // 非所有动物都会飞
}
class Pig implements Animal {
@Override public void eat() { /* ... */ }
@Override public void fly() { throw new UnsupportedOperationException(); } // 强制实现无用方法
}
重构:
// 拆分为独立接口
public interface EatAble { void eat(); }
public interface FlyAble { void fly(); }
class Pig implements EatAble { /* 仅实现进食 */ }
class Bird implements EatAble, FlyAble { /* 实现两种能力 */ }
三、设计模式在 Java 生态中的典型应用
3.1 JDK 中的模式实践
模式 | JDK 类 / 方法 | 应用场景 |
---|---|---|
工厂模式 | Calendar.getInstance() | 创建不同时区的日历实例 |
单例模式 | Runtime.getRuntime() | 全局唯一运行时环境 |
观察者模式 | Observable/Observer | AWT 事件监听机制 |
3.2 Spring 框架中的模式应用
- 工厂模式:
// BeanFactory创建Bean实例
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
UserService userService = context.getBean("userService", UserService.class);
- 代理模式:
// AOP实现方法增强
@Transactional
public void createOrder() { /* 订单创建 */ }
- 模板方法:
// JdbcTemplate简化数据库操作
jdbcTemplate.query("SELECT * FROM USER", (rs) -> new User(rs.getInt("id")));
3.3 Spring 框架深度模式解析
3.3.1 装饰器模式(Decorator Pattern)
框架应用:
-
BeanPostProcessor:增强 Bean 功能(如 AOP 代理生成)
-
HandlerInterceptor:请求处理链增强(日志记录、权限校验)
源码解析:
// BeanPostProcessor装饰器链
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName);
Object postProcessAfterInitialization(Object bean, String beanName);
}
// 典型实现:ProxyProcessorSupport(生成AOP代理)
protected Object postProcessAfterInitialization(Object bean, String beanName) {
if (!this.targetSourcedBeans.contains(beanName)) {
return createProxy(bean, beanName, specificInterceptors, new SingletonTargetSource(bean));
}
return bean;
}
3.3.2 策略模式(Strategy Pattern)
应用场景:
-
事务管理策略:PlatformTransactionManager支持不同事务源(JTA/DataSource)
-
消息转换器:HttpMessageConverter支持多种数据格式(JSON/XML)
配置示例:
// 声明不同事务策略
@Bean
public PlatformTransactionManager jtaTransactionManager() {
return new JtaTransactionManager();
}
@Bean
public PlatformTransactionManager dataSourceTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// 根据环境选择策略
@Service
public class OrderService {
@Autowired
private PlatformTransactionManager transactionManager;
}
3.3.3 责任链模式(Chain of Responsibility Pattern)
核心实现:
-
Filter 链:DispatcherServlet处理请求的过滤器链(DelegatingFilterProxy)
-
异常处理链:HandlerExceptionResolver处理不同类型异常
请求处理流程:
graph LR
A[客户端请求] --> B(DispatcherServlet)
B --> C[HandlerMapping]
C --> D[HandlerAdapter]
D --> E[HandlerInterceptor.preHandle]
E --> F[目标Controller]
F --> G[HandlerInterceptor.postHandle]
G --> H[ViewResolver]
3.4 Spring Boot 自动配置中的模式应用
3.4.1 工厂模式(Factory Pattern)
自动配置原理:
-
EnableAutoConfiguration
通过AutoConfigurationImportSelector
加载配置类 -
@ConditionalOnMissingBean
避免重复创建 Bean
案例:数据库连接池自动配置
// DataSourceAutoConfiguration
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().type(this::getDataSourceType).build();
}
3.4.2 模板方法(Template Method)
核心抽象类:
-
AbstractApplicationContex
t:模板方法refresh()定义容器启动流程 -
RepositoryRestConfigurer
:提供扩展点供用户自定义
容器启动模板:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
// 模板方法扩展点
onRefresh();
}
}
protected void onRefresh() { /* 子类实现 */ }
}
3.5 Spring Cloud 中的模式实践
3.5.1 代理模式(Proxy Pattern)
OpenFeign 远程调用:
-
通过动态代理生成 HTTP 客户端
-
整合 Ribbon 负载均衡与 Sentinel 熔断
代理生成逻辑:
// FeignClientFactoryBean
public Object getObject() throws Exception {
return getTarget();
}
<T> T getTarget() {
FeignContext context = applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
// 生成代理对象
return (T) builder.target(type, getUrl());
}
3.5.2 责任链模式(Filter Chain)
Spring Cloud Gateway:
-
路由过滤器链实现请求转换(鉴权 / 限流 / 参数校验)
-
支持自定义过滤器顺序(Ordered接口)
配置示例:
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- name: RequestRateLimiter
args:
key-resolver: "#{@ipKeyResolver}"
- name: HeaderFilter
args:
request-headers-to-add:
- name: X-Request-Id
value: "#{UUID.randomUUID().toString()}"
四、企业级框架模式应用对比(新增章节)
4.1 主流框架模式使用频率统计
模式类型 | Spring Framework | Spring Boot | Spring Cloud | MyBatis |
---|---|---|---|---|
工厂模式 | ★★★★☆ | ★★★★★ | ★★★★☆ | ★★★☆☆ |
代理模式 | ★★★★★ | ★★★☆☆ | ★★★★★ | ★★★★☆ |
模板方法 | ★★★☆☆ | ★★★☆☆ | ★★☆☆☆ | ★★★★☆ |
责任链模式 | ★★★☆☆ | ★★☆☆☆ | ★★★★☆ | ★★☆☆☆ |
4.2 模式选择决策树(Spring 场景)
graph TD
A[是否需要对象创建逻辑封装?] -->|是| B{简单创建?}
B -->|是| C[工厂模式]
B -->|复杂创建| D[建造者模式]
A -->|否| E[是否需要功能增强?]
E -->|是| F[代理/装饰器模式]
E -->|否| G[是否需要算法动态切换?]
G -->|是| H[策略模式]
G -->|否| I[是否需要流程控制?]
I -->|是| J[责任链/模板方法]
4.3 常见误区
-
过度设计:简单场景滥用模式(如单例用于无状态工具类)
-
忽视原则:优先满足模式结构而违背 SOLID 原则
-
脱离场景:不结合业务需求选择模式(如用工厂模式处理简单对象创建)
五、模式应用最佳实践(Spring 场景)
5.1 避免模式误用的三个原则
-
优先原则而非模式:先满足 SOLID 原则,再考虑模式实现
- 反例:为使用工厂模式而强行拆分简单类
-
结合框架特性:利用 Spring 现有模式扩展点(如@Conditional替代硬编码条件判断)
-
控制复杂度:单个类模式应用不超过 2 种(避免过度设计)
5.2 模式组合使用案例
场景:实现可扩展的日志系统
-
工厂模式:创建不同日志处理器(文件 / 数据库 / 控制台)
-
策略模式:动态切换日志级别(DEBUG/INFO/ERROR)
-
装饰器模式:为日志处理器添加加密 / 压缩功能
实现架构:
// 工厂创建策略实例
LoggerFactory.getLogger(Strategy.LOCAL_FILE);
// 装饰器增强功能
Logger logger = new EncryptDecorator(new CompressDecorator(logger));
通过补充 Spring 及扩展框架中的模式应用,开发者能更深入理解设计模式在实际框架中的落地方式。这些案例不仅展示了模式的具体实现,更体现了如何通过模式组合解决复杂问题。下一篇我们将进入创建型模式专题,详细解析单例模式的线程安全实现与工厂模式的扩展应用。
设计模式的核心不是记忆 23 种模板,而是培养 “识别问题→匹配方案→验证原则” 的思维方式:
- 识别重复问题:发现代码中相似的设计痛点(如硬编码策略)
- 匹配成熟方案:从模式库中选择最适合的解决方案(如策略模式替代大量条件判断)
- 验证设计原则:确保实现符合 SOLID 原则(如依赖倒置保证扩展性)
通过后续系列博客,我们将深入每种模式的实现细节,并结合 Spring、微服务等实战场景,演示如何用模式思维解决复杂系统设计问题。