写在前面
❝
Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!
初期实现
系统背景与设计目标
电商平台需快速上线用户登录功能,初期核心需求包括:
- 用户身份验证(
login
) - 用户信息查询(
getUserById
)
开发团队采用直接实现模式
,在10个工作日内交付了基础功能。
初始代码结构
1. 抽象接口定义
arduino
public interface UserService {
void login(String username, String password);
String getUserById(Integer userId);
}
2. 核心业务实现
typescript
class UserServiceImpl implements UserService {
@Override
public void login(String username, String password) {
System.out.println("验证用户:" + username + " 登录成功");
}
@Override
public String getUserById(Integer userId) {
return "用户ID:" + userId + " 的详细信息";
}
}
3. 测试验证
makefile
验证用户:admin 登录成功
用户ID:1 的详细信息
需求变更:安全与审计要求
系统上线3个月后,安全团队提出新需求:
权限分级 :仅允许admin
用户执行登录操作
操作审计:记录所有敏感操作的执行日志
快速实现方案
typescript
public class UserServiceImpl implements UserService {
@Override
public void login(String username, String password) {
// 硬编码权限校验
if (!"admin".equals(username)) {
System.out.println("无访问权限!");
return;
}
System.out.println("验证用户:" + username + " 登录成功");
System.out.println("[日志] 用户登录操作: " + username); // 日志耦合
}
}
架构隐患分析
问题现象 | 潜在风险 |
---|---|
业务逻辑包含权限校验代码 | 修改权限策略需重新部署核心服务 |
日志记录散落在各个方法 | 新增日志字段需修改所有业务方法 |
功能扩展需修改既有实现 | 20%业务代码+80%辅助代码的维护困境 |
第二话:代理模式重构实践
重构目标
- 关注点分离:业务代码仅处理用户验证/信息查询
- 非侵入扩展:新增功能不修改原有实现类
- 标准化接入:权限、日志等模块可插拔替换
代理模式三大核心
角色 | 职责说明 | 案例对应 |
---|---|---|
Subject | 定义业务接口规范 | UserService 接口 |
RealSubject | 实现核心业务逻辑 | UserServiceImpl 类 |
Proxy | 控制访问并增强功能 | UserServiceProxy 代理类 |
静态代理实现方案
代理类结构
typescript
public class UserServiceProxy implements UserService {
private final UserService realService;
public UserServiceProxy(UserService realService) {
this.realService = realService;
}
@Override
public void login(String username, String password) {
checkPermission(username); // 前置增强
realService.login(username, password);
logOperation("login", username); // 后置增强
}
// 权限校验模块化
private void checkPermission(String username) {
if (!"admin".equals(username))
throw new SecurityException("权限验证失败");
System.out.println("✅ 权限校验通过");
}
// 日志记录标准化
private void logOperation(String operation, String params) {
System.out.printf("[AUDIT] %s - params: %s%n", operation, params);
}
}
测试验证与执行效果
typescript
public class ProxyTest {
public static void main(String[] args) {
UserService service = new UserServiceProxy(new UserServiceImpl());
service.login("admin", "123456");
System.out.println(service.getUserById(1));
}
}
输出结果:
csharp
✅ 权限校验通过
验证用户:admin 登录成功
[AUDIT] login - params: admin
用户ID:1 的详细信息
架构演进对比
维度 | 初始实现 | 代理模式实现 |
---|---|---|
代码结构 | 业务与辅助逻辑混杂 | 业务/辅助逻辑分层 |
维护成本 | 修改1个功能需改动所有相关方法 | 新增代理类即可扩展功能 |
测试难度 | 需模拟完整环境测试耦合逻辑 | 可独立测试业务类和代理类 |
扩展性 | 新增功能导致类膨胀 | 符合开闭原则,通过组合实现功能增强 |
长话短说
设计本质
通过中间层代理实现关注点分离,遵循开闭原则,将核心业务与辅助功能解耦,提升系统的可维护性和扩展性。
代理类型选择
- 静态代理:接口方法较少且固定
- 动态代理:接口方法多或需要通用处理
- CGLIB代理:需要代理无接口的类
典型应用场景
- 安全代理:统一权限校验(如Spring Security)
- 虚拟代理:延迟加载大资源(如图片预加载)
- 智能引用:实现缓存机制(如MyBatis Mapper)
实施步骤
- 识别需要增强的功能边界(如日志/权限)
- 通过接口抽象核心业务能力
- 创建代理类委托调用真实对象
- 在代理方法中插入横切逻辑
- 客户端通过代理访问服务
优势总结
- 解耦业务逻辑与横切关注点
- 提高代码复用性和可维护性
- 支持动态功能扩展
- 符合开闭原则设计原则