Java中多方法重复相同条件判断的优化:命令模式之外的更佳方案及可读性与DRY原则评估
好问题!针对你这种大量方法需要共享同一前置校验逻辑的场景,确实有几种比当前命令模式更简洁、可读性更强的方案,同时也能很好地遵循DRY原则。咱们一步步来分析:
先聊聊你当前的命令模式实现
你的思路是对的——把重复的校验逻辑抽离到统一的地方,但这个方案也有明显的缺点:每个方法都要创建匿名内部类,模板代码冗余度高,当后续新增方法越来越多时,重复的new ValidCommand(...)代码会越来越多,可读性和维护性都会打折扣。所以这个方案不是当前场景下的最优解。
更优的实现方案推荐
1. 优先选择:AOP(面向切面编程)
这是处理这类横切关注点(比如前置校验、日志、事务)最经典的方案,完美契合你的场景:
- 把校验逻辑集中到一个切面里,所有需要校验的方法只需要加个注解即可
- 新增方法时,只需要加注解,完全消除重复代码
- 校验逻辑修改时,只需要改切面,不用动所有业务方法
举个Spring AOP的实现例子:
首先定义一个标记用的注解:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RequiresCondition { }
然后编写切面类,统一处理校验:
@Aspect @Component public class ConditionCheckAspect { // 拦截所有带@RequiresCondition注解的方法,同时获取aLong和aString参数 @Before("@annotation(RequiresCondition) && args(aLong, aString, ..)") public void checkCondition(Long aLong, String aString) { if (!validate(aLong, aString)) { throw new CustomException(); } } // 复用原有的校验逻辑 private boolean validate(Long aLong, String aString) { // 原condition方法的代码 return true; } }
最后改造你的业务类,代码会变得极其简洁:
public class MyClass { @RequiresCondition public ClassA method1(Long aLong, String aString, ...) { return doSomething(...); } @RequiresCondition public void method2(Long aLong, String aString, ...) { doSomethingElse(...); } @RequiresCondition public List<ClassB> method3(Long aLong, String aString, ...) { return doSomethingDifferent(...); } }
如果你的项目没有用Spring,也可以用AspectJ的编译时织入来实现AOP,效果是一样的。
2. 轻量替代:函数式接口+模板方法
如果不想引入AOP,用Java 8及以上的函数式接口可以大幅简化命令模式的冗余代码:
通过定义通用的模板方法,把校验和执行逻辑分离,用Lambda表达式传递业务逻辑。
代码示例:
public class MyClass { // 原有的校验逻辑 private boolean condition(Long aLong, String aString) { return true; } // 通用模板方法:带返回值的场景 private <T> T executeIfValid(Long aLong, String aString, Supplier<T> action) { if (condition(aLong, aString)) { return action.get(); } throw new CustomException(); } // 通用模板方法:无返回值的场景 private void executeIfValid(Long aLong, String aString, Runnable action) { if (condition(aLong, aString)) { action.run(); } throw new CustomException(); } // 业务方法变得简洁清晰 public ClassA method1(Long aLong, String aString, ...) { return executeIfValid(aLong, aString, () -> doSomething(...)); } public void method2(Long aLong, String aString, ...) { executeIfValid(aLong, aString, () -> doSomethingElse(...)); } public List<ClassB> method3(Long aLong, String aString, ...) { return executeIfValid(aLong, aString, () -> doSomethingDifferent(...)); } }
这个方案比命令模式轻量太多,没有多余的抽象类和匿名内部类,Lambda表达式也很直观,新增方法时只需要调用模板方法即可。
总结:当前命令模式是否值得采用?
如果是Java 8之前的老项目,命令模式是合理的选择,但在现代Java环境下,它就显得笨重了:
- 代码冗余度高,每个方法都要写匿名内部类
- 相比AOP和函数式模板,可读性和维护性都更差
所以更推荐你根据项目情况选择上面两种方案:
- 有Spring环境:优先用AOP,扩展性和简洁性拉满
- 不想用AOP:函数式模板方法,轻量且易维护
内容的提问来源于stack exchange,提问作者tsiskoS
相关产品推荐
相关产品推荐

