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

262 阅读3分钟

本文是「EduCore 教务系统实战系列」第 4 篇,将通过实际代码案例,详解我如何使用策略模式优化多角色登录认证流程,实现登录逻辑的解耦与扩展。


🎯 背景:多角色登录如何设计更优雅?

在 EduCore 教务系统中,存在以下三种角色需要登录:

  • ADMIN(管理员)
  • TEACHER(教师)
  • STUDENT(学生)

如果不使用任何设计模式,登录接口代码大概率会是这样的:

@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),代码不具备良好扩展性;
  • 测试与调试困难,逻辑集中耦合,不利于单元测试;

✅ 引入策略模式解决耦合问题

策略模式是一种行为型设计模式,它允许在运行时选择算法或行为。

我们可以为每种角色登录逻辑抽象成一个策略类,接口如下:

public interface LoginStrategy {
    Account login(Account account);
}

🧱 代码实现步骤

Step 1️⃣ 定义统一策略接口

public interface LoginStrategy {
    Account login(Account account);
}

Step 2️⃣ 各角色实现策略逻辑

@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️⃣ 创建策略工厂类

@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️⃣ 控制器使用工厂调度策略

@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 名来避免硬编码。


📦 项目结构片段

├── strategy
│   ├── LoginStrategy.java
│   ├── AdminLoginStrategy.java
│   ├── TeacherLoginStrategy.java
│   └── StudentLoginStrategy.java
├── factory
│   └── LoginStrategyFactory.java
├── controller
│   └── LoginController.java

🔚 总结

通过引入策略模式,我实现了:

  • ✅ 多角色登录逻辑完全解耦;
  • ✅ 角色扩展无需修改核心控制器;
  • ✅ 每个策略可单独调试、测试;
  • ✅ 构建了一套更优雅、更工程化的认证体系;

这种设计也为后续引入责任链模式、模板方法、缓存优化等打下良好基础。


📌 下一篇预告

📌《无微信依赖!纯网页扫码登录实现方案详解》

你将看到一个不依赖微信或 App 的纯网页扫码登录功能,适配 PC 和手机浏览器,完全自主可控。


🔗 项目源码地址


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

  • 点个赞 👍
  • 收藏 ⭐
  • 关注我 👇 获取后续实战文章更新