本文是「EduCore 教务系统实战系列」第 4 篇,将通过实际代码案例,详解我如何使用策略模式优化多角色登录认证流程,实现登录逻辑的解耦与扩展。
🎯 背景:多角色登录如何设计更优雅?
在 EduCore 教务系统中,存在以下三种角色需要登录:
ADMIN(管理员)TEACHER(教师)STUDENT(学生)
如果不使用任何设计模式,登录接口代码大概率会是这样的:
java
@PostMapping("/login")
public R login(@RequestBody Account account) {
Account dbAccount = null;
if ("ADMIN".equals(account.getRole())) {
dbAccount = adminService.login(account);
} else if ("TEACHER".equals(account.getRole())) {
dbAccount = teacherService.login(account);
} else if ("STUDENT".equals(account.getRole())) {
dbAccount = studentService.login(account);
}
if (dbAccount == null) return R.error("账号或密码错误");
String token = jwtUtils.createToken(dbAccount);
return R.ok().put("token", token).put("user", dbAccount);
}
你可以看到这段代码的问题:
- ❌ 角色判断耦合严重,一旦新增角色,必须修改这里;
- ❌ 服务逻辑难以扩展,不同角色有不同校验规则或来源;
- ❌ 不符合开闭原则(OCP),代码不具备良好扩展性;
- ❌ 测试与调试困难,逻辑集中耦合,不利于单元测试;
✅ 引入策略模式解决耦合问题
策略模式是一种行为型设计模式,它允许在运行时选择算法或行为。
我们可以为每种角色登录逻辑抽象成一个策略类,接口如下:
java
public interface LoginStrategy {
Account login(Account account);
}
🧱 代码实现步骤
Step 1️⃣ 定义统一策略接口
java
public interface LoginStrategy {
Account login(Account account);
}
Step 2️⃣ 各角色实现策略逻辑
java
@Component("ADMIN")
public class AdminLoginStrategy implements LoginStrategy {
@Autowired private AdminService adminService;
@Override
public Account login(Account account) {
return adminService.login(account);
}
}
@Component("TEACHER")
public class TeacherLoginStrategy implements LoginStrategy {
@Autowired private TeacherService teacherService;
@Override
public Account login(Account account) {
return teacherService.login(account);
}
}
@Component("STUDENT")
public class StudentLoginStrategy implements LoginStrategy {
@Autowired private StudentService studentService;
@Override
public Account login(Account account) {
return studentService.login(account);
}
}
💡 说明:
- 每个策略只关心自己角色的登录逻辑;
- 各服务如
adminService.login()可做密码加密校验、账号冻结判断等扩展逻辑;
Step 3️⃣ 创建策略工厂类
java
@Component
public class LoginStrategyFactory {
@Autowired
private Map<String, LoginStrategy> strategyMap;
public LoginStrategy getStrategy(String role) {
LoginStrategy strategy = strategyMap.get(role);
if (strategy == null) {
throw new IllegalArgumentException("Unsupported role: " + role);
}
return strategy;
}
}
🧠 Spring 会自动将 @Component("ADMIN") 等注入为 Map,key 为 Bean 名称,value 为实现类。
Step 4️⃣ 控制器使用工厂调度策略
java
@RestController
@RequestMapping("/auth")
public class LoginController {
@Autowired
private LoginStrategyFactory loginStrategyFactory;
@Autowired
private JwtUtils jwtUtils;
@PostMapping("/login")
public R login(@RequestBody Account account) {
LoginStrategy strategy = loginStrategyFactory.getStrategy(account.getRole());
Account dbAccount = strategy.login(account);
if (dbAccount == null) return R.error("账号或密码错误");
String token = jwtUtils.createToken(dbAccount);
return R.ok().put("token", token).put("user", dbAccount);
}
}
🌱 效果对比总结
| 对比维度 | 原始 if-else 实现 | 策略模式实现 |
|---|---|---|
| 可读性 | 低(if 嵌套复杂) | 高(逻辑分离) |
| 扩展性 | 差,新增角色要改 controller | 强,新增策略类即可 |
| 测试性 | 较差 | 容易单测每个策略 |
| 开闭原则 | 不符合 | 完全符合 |
🧠 常见问题解答
❓ 策略模式是否会影响性能?
不会。Spring 的依赖注入在启动阶段完成,调用时只涉及 Map 查找与方法调用,性能开销可以忽略。
❓ 角色名作为 Bean 名是否不太优雅?
可以封装为 Enum 并加校验;或用 @Qualifier 指定 Bean 名来避免硬编码。
📦 项目结构片段
plaintext
├── strategy
│ ├── LoginStrategy.java
│ ├── AdminLoginStrategy.java
│ ├── TeacherLoginStrategy.java
│ └── StudentLoginStrategy.java
├── factory
│ └── LoginStrategyFactory.java
├── controller
│ └── LoginController.java
🔚 总结
通过引入策略模式,我实现了:
- ✅ 多角色登录逻辑完全解耦;
- ✅ 角色扩展无需修改核心控制器;
- ✅ 每个策略可单独调试、测试;
- ✅ 构建了一套更优雅、更工程化的认证体系;
这种设计也为后续引入责任链模式、模板方法、缓存优化等打下良好基础。
📌 下一篇预告
📌《无微信依赖!纯网页扫码登录实现方案详解》
你将看到一个不依赖微信或 App 的纯网页扫码登录功能,适配 PC 和手机浏览器,完全自主可控。
🔗 项目源码地址
- GitHub:gitee.com/codevibe/gr...
- 策略模式全部实现已上传,欢迎查阅、提 Issue
🙋♂️ 如果你觉得这篇文章有帮助:
- 点个赞 👍
- 收藏 ⭐
- 关注我 👇 获取后续实战文章更新