项目中如何用策略模式实现多角色登录解耦?(附实战代码)

本文是「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 和手机浏览器,完全自主可控。


🔗 项目源码地址


🙋‍♂️ 如果你觉得这篇文章有帮助:

  • 点个赞 👍
  • 收藏 ⭐
  • 关注我 👇 获取后续实战文章更新
相关推荐
一 乐16 小时前
婚纱摄影网站|基于ssm + vue婚纱摄影网站系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端
Boilermaker199216 小时前
[Java 并发编程] Synchronized 锁升级
java·开发语言
Cherry的跨界思维16 小时前
28、AI测试环境搭建与全栈工具实战:从本地到云平台的完整指南
java·人工智能·vue3·ai测试·ai全栈·测试全栈·ai测试全栈
alonewolf_9917 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
一嘴一个橘子17 小时前
spring-aop 的 基础使用(啥是增强类、切点、切面)- 2
java
码事漫谈17 小时前
Protocol Buffers 编码原理深度解析
后端
sheji341617 小时前
【开题答辩全过程】以 中医药文化科普系统为例,包含答辩的问题和答案
java
码事漫谈17 小时前
gRPC源码剖析:高性能RPC的实现原理与工程实践
后端
恋爱绝缘体118 小时前
2020重学C++重构你的C++知识体系
java·开发语言·c++·算法·junit
wszy180918 小时前
新文章标签:让用户一眼发现最新内容
java·python·harmonyos