Java如何优化授权校验代码使其更符合面向对象设计规范?
面向对象改造方案(策略模式+工厂派发)
现有代码核心缺陷
isAuthValid方法耦合了所有授权类型的分支判断,随着授权类型增加会无限膨胀,维护成本极高- 违反开闭原则:新增授权类型必须修改原有方法的分支逻辑,极易引入存量功能bug
- 并行流场景下使用普通
toMap收集器存在并发风险 - 不同类型的校验逻辑没有独立封装,无法针对单种授权类型做独立单元测试
改造步骤
1. 定义统一的授权校验策略接口
所有授权类型的校验逻辑都遵循这个接口规范,从根源上消除分支判断的必要:
public interface AuthValidityChecker { // 返回当前校验器支持的授权类型 AuthType supportType(); // 执行对应类型的授权有效性校验 boolean check(AuthorizationValue authValue); }
建议把原有代码中的常量AUTH_TYPE_A/AUTH_TYPE_B/AUTH_TYPE_C统一收敛为AuthType枚举值,避免魔法值问题。
2. 为每种授权类型实现独立的校验策略
把原来散落在isAuthTypeAValid/isAuthTypeBValid等方法里的逻辑,拆分到独立的实现类中,每个类只负责一种授权类型的校验:
// A类型授权校验器 public class TypeAAuthChecker implements AuthValidityChecker { // 按需注入校验需要的远程客户端、配置等依赖 private final RemoteAuthClient remoteAuthClient; public TypeAAuthChecker(RemoteAuthClient remoteAuthClient) { this.remoteAuthClient = remoteAuthClient; } @Override public AuthType supportType() { return AuthType.AUTH_TYPE_A; } @Override public boolean check(AuthorizationValue authValue) { // 迁移原有isAuthTypeAValid的全部逻辑到这里 return remoteAuthClient.validateTypeA(authValue); } } // B类型授权校验器 public class TypeBAuthChecker implements AuthValidityChecker { private final RemoteAuthClient remoteAuthClient; public TypeBAuthChecker(RemoteAuthClient remoteAuthClient) { this.remoteAuthClient = remoteAuthClient; } @Override public AuthType supportType() { return AuthType.AUTH_TYPE_B; } @Override public boolean check(AuthorizationValue authValue) { // 迁移原有isAuthTypeBValid的全部逻辑到这里 return remoteAuthClient.validateTypeB(authValue); } } // C类型授权校验器 public class TypeCAuthChecker implements AuthValidityChecker { private final RemoteAuthClient remoteAuthClient; public TypeCAuthChecker(RemoteAuthClient remoteAuthClient) { this.remoteAuthClient = remoteAuthClient; } @Override public AuthType supportType() { return AuthType.AUTH_TYPE_C; } @Override public boolean check(AuthorizationValue authValue) { // 迁移原有isAuthTypeCValid的全部逻辑到这里 return remoteAuthClient.validateTypeC(authValue); } }
3. 实现校验策略工厂,完成自动派发
工厂类负责维护「授权类型-对应校验器」的映射,对外提供统一的校验入口,不需要任何if-else判断:
public class AuthCheckerFactory { private final Map<AuthType, AuthValidityChecker> checkerMap; // 如果你使用Spring等IOC容器,可直接注入所有AuthValidityChecker实现类,无需手动注册 public AuthCheckerFactory(List<AuthValidityChecker> checkers) { this.checkerMap = checkers.stream() .collect(Collectors.toUnmodifiableMap( AuthValidityChecker::supportType, Function.identity() )); } // 无IOC场景的构造方法,手动注册所有校验器 public AuthCheckerFactory(RemoteAuthClient remoteAuthClient) { this.checkerMap = Map.of( AuthType.AUTH_TYPE_A, new TypeAAuthChecker(remoteAuthClient), AuthType.AUTH_TYPE_B, new TypeBAuthChecker(remoteAuthClient), AuthType.AUTH_TYPE_C, new TypeCAuthChecker(remoteAuthClient) ); } public boolean isValid(AuthorizationValue authValue) { AuthValidityChecker checker = checkerMap.get(authValue.getType()); // 无匹配校验器时返回false,和原有逻辑保持一致 return checker != null && checker.check(authValue); } }
4. 简化原有流处理逻辑
替换原来的isAuthValid调用,同时修复并行流的收集器问题:
// 初始化工厂,可通过依赖注入获取实例 private final AuthCheckerFactory authCheckerFactory = new AuthCheckerFactory(remoteAuthClient); private Map<UUID, Boolean> getAuthorizationValidityMap(UUID accountId) { return findCredentialsByAccountId(accountId) .parallelStream() .collect(Collectors.toConcurrentMap( AuthorizationValue::getId, authCheckerFactory::isValid )); }
方案收益
- 完全符合开闭原则:后续新增授权类型,只需要新增一个对应的
AuthValidityChecker实现类,不需要修改任何原有校验、派发逻辑,无侵入风险 - 职责单一:每个校验类只负责一种授权类型的校验逻辑,代码不会随业务迭代无限膨胀,单元测试可单独覆盖每个校验规则
- 性能更优:类型到校验器的映射在工厂初始化时一次性构建,校验时的派发效率为O(1),比多层if-else串行判断性能更好
- 依赖管理更清晰:每个校验器可以单独注入自己需要的依赖,不需要把所有依赖都堆在同一个校验类里
注意:如果你的授权值类型判断逻辑不是基于固定的类型字段,也可以把策略匹配逻辑改成
boolean support(AuthorizationValue authValue),支持更灵活的匹配规则,核心派发逻辑不变。
内容的提问来源于stack exchange,提问作者Billy Keef
相关产品推荐
相关产品推荐

