Java中如何限制Node接口方法传入未实现QueryEngine参数时的调用
方案1:统一校验逻辑,避免散落至各实现类
核心思路是新增一层抽象父类封装通用校验逻辑,禁止子类直接覆写getValue入口方法,从语法层面保证校验逻辑不会遗漏:
public abstract class AbstractNode implements Node { // 子类实现返回自身支持的QueryEngine列表 protected abstract Set<QueryEngine> listSupportedEngines(); // 子类实现自身的业务逻辑,无需处理校验 protected abstract <T> T doGetValue(QueryEngine engine, Class<T> context); @Override public final <T> T getValue(QueryEngine engine, Class<T> context) { // 统一校验逻辑:不支持的engine直接抛出异常,禁止调用 if (!listSupportedEngines().contains(engine)) { throw new UnsupportedOperationException( String.format("当前Node实现不支持QueryEngine类型:%s", engine.name()) ); } return doGetValue(engine, context); } }
现有实现类改造步骤:
- 所有原来实现
Node接口的抽象/普通类改为继承AbstractNode - 把原有
getValue方法的业务逻辑迁移到doGetValue中 - 实现
listSupportedEngines返回自身支持的QueryEngine(比如当前所有实现只返回Set.of(QueryEngine.VALUE1)即可)
改造后所有校验逻辑收敛在父层,不需要每个实现类重复编写判断逻辑。
方案2:可插拔的平台特定重写实现
核心采用策略模式+Java SPI实现无侵入的扩展能力,不需要修改现有核心代码即可新增/替换QueryEngine的实现:
步骤1:抽离QueryEngine处理策略接口
public interface NodeEngineStrategy { // 声明当前策略支持的QueryEngine类型 QueryEngine supportedEngine(); // 对应类型的业务处理逻辑 <T> T handle(AbstractNode node, QueryEngine engine, Class<T> context); }
步骤2:实现默认策略(对应现有VALUE1的逻辑)
public class Value1EngineStrategy implements NodeEngineStrategy { @Override public QueryEngine supportedEngine() { return QueryEngine.VALUE1; } @Override public <T> T handle(AbstractNode node, QueryEngine engine, Class<T> context) { // 原有getValue1CustomFunction的逻辑迁移到此处 String expression = String.format(Value1_PATTERN, node.getArguments().get(0).getValue(engine, String.class)); return queryBuilder(context, expression); } }
步骤3:父类中加载策略
public abstract class AbstractNode implements Node { // 缓存所有已加载的策略,key为QueryEngine private static final Map<QueryEngine, NodeEngineStrategy> ENGINE_STRATEGY_MAP = new HashMap<>(); static { // SPI加载所有classpath下的策略实现 ServiceLoader<NodeEngineStrategy> loader = ServiceLoader.load(NodeEngineStrategy.class); for (NodeEngineStrategy strategy : loader) { ENGINE_STRATEGY_MAP.put(strategy.supportedEngine(), strategy); } } @Override public final <T> T getValue(QueryEngine engine, Class<T> context) { NodeEngineStrategy strategy = ENGINE_STRATEGY_MAP.get(engine); if (strategy == null) { throw new UnsupportedOperationException( String.format("未找到QueryEngine类型:%s的对应实现", engine.name()) ); } // 支持子类自定义覆盖默认策略 NodeEngineStrategy customStrategy = getCustomStrategy(engine); if (customStrategy != null) { return customStrategy.handle(this, engine, context); } return strategy.handle(this, engine, context); } // 子类可选实现,用于自定义特定QueryEngine的处理逻辑 protected NodeEngineStrategy getCustomStrategy(QueryEngine engine) { return null; } // 抽象方法提供给策略获取Node的属性,比如参数列表等 public abstract List<Node> getArguments(); }
可插拔扩展方式
新增QueryEngine支持时,只需要新增NodeEngineStrategy的实现类,在classpath的META-INF/services/com.xxx.NodeEngineStrategy文件中添加实现类的全限定名即可自动加载,不需要修改原有Node的代码。
平台特定实现只要替换对应策略的jar包即可,无需改动核心逻辑。
内容的提问来源于stack exchange,提问作者KVM
相关产品推荐
相关产品推荐

