Java中如何实现支持多类型返回的统一InformationSet查询方法?
针对你的问题——想实现一个统一的ask()方法处理两种不同返回类型的查询,而不用在UI层判断类型,这里有几个非常适合Java场景的可行方案:
方案1:封装通用结果类(最直观的传统方案)
创建一个通用的查询结果类,把返回值的类型和数据都封装进去,这样ask()方法只需要返回这个统一的对象,调用方可以根据类型标识提取对应的数据。
首先定义QueryResult类:
public class QueryResult implements Serializable { // 标识结果类型:FACT_CHECK(返回布尔)或 IMPLIANT_CHECK(返回Fact列表) public enum ResultType { FACT_CHECK, IMPLIANT_CHECK } private final ResultType type; private final Boolean factCheckResult; private final List<Fact> impliantCheckResults; // 私有构造,用静态工厂方法创建 private QueryResult(ResultType type, Boolean factCheckResult, List<Fact> impliantCheckResults) { this.type = type; this.factCheckResult = factCheckResult; this.impliantCheckResults = impliantCheckResults != null ? new ArrayList<>(impliantCheckResults) : null; } // 静态工厂方法:创建事实校验结果 public static QueryResult ofFactCheck(boolean result) { return new QueryResult(ResultType.FACT_CHECK, result, null); } // 静态工厂方法:创建推导校验结果 public static QueryResult ofImpliantCheck(List<Fact> results) { return new QueryResult(ResultType.IMPLIANT_CHECK, null, results); } // Getter方法 public ResultType getType() { return type; } public Boolean getFactCheckResult() { return factCheckResult; } public List<Fact> getImpliantCheckResults() { return impliantCheckResults; } }
然后在InformationSet里实现ask()方法:
public class InformationSet { // 假设已有的Fact和Rule存储逻辑 private List<Fact> facts = new ArrayList<>(); private List<Rule> rules = new ArrayList<>(); public QueryResult ask(Question question) { if ("?".equals(question.getOperator())) { // 处理事实校验逻辑,得到boolean结果 boolean result = checkFact(question.getQuestionFact()); return QueryResult.ofFactCheck(result); } else if ("=>".equals(question.getOperator())) { // 处理推导校验逻辑,得到Fact列表 List<Fact> results = deriveFacts(question.getQuestionFact()); return QueryResult.ofImpliantCheck(results); } else { throw new InvalidOperatorException("Unknown operator: " + question.getOperator()); } } // 以下是你已有的业务逻辑方法示例 private boolean checkFact(Fact fact) { // 实现事实校验的逻辑:查找匹配的Fact返回真值 return facts.stream() .filter(f -> matchFact(f, fact)) .findFirst() .map(Fact::isTruth) .orElse(false); } private List<Fact> deriveFacts(Fact fact) { // 实现推导逻辑:应用规则生成对应的Fact列表 List<Fact> derived = new ArrayList<>(); for (Rule rule : rules) { // 这里省略规则匹配和推导的具体逻辑 if (matchRule(rule, fact)) { Fact derivedFact = createDerivedFact(rule, fact); derived.add(derivedFact); } } return derived; } // 辅助方法:判断两个Fact是否匹配(属性一致) private boolean matchFact(Fact f1, Fact f2) { // 实现属性匹配逻辑 return true; } private boolean matchRule(Rule rule, Fact fact) { // 实现规则与Fact的匹配逻辑 return true; } private Fact createDerivedFact(Rule rule, Fact fact) { // 实现根据规则生成推导Fact的逻辑 return new Fact(); } }
调用时,UI层只需根据结果类型处理数据:
InformationSet infoSet = new InformationSet(); Question question = new Question(someFact, "?"); QueryResult result = infoSet.ask(question); switch (result.getType()) { case FACT_CHECK: boolean isTrue = result.getFactCheckResult(); // 处理布尔结果 break; case IMPLIANT_CHECK: List<Fact> derivedFacts = result.getImpliantCheckResults(); // 处理Fact列表 break; }
这个方案兼容性好,支持所有Java版本,逻辑清晰易维护。
方案2:使用回调/策略模式(解耦处理逻辑)
如果不想在UI层做类型判断,可以让调用方传入对应的回调接口,ask()方法内部根据查询类型直接调用回调处理结果,无需返回值。
首先定义两个回调接口:
// 事实校验的回调 @FunctionalInterface public interface FactCheckCallback { void onResult(boolean result); } // 推导校验的回调 @FunctionalInterface public interface ImpliantCheckCallback { void onResult(List<Fact> results); }
然后修改InformationSet的ask()方法:
public class InformationSet { // 已有的存储和业务逻辑... public void ask(Question question, FactCheckCallback factCallback, ImpliantCheckCallback impliantCallback) { if ("?".equals(question.getOperator())) { boolean result = checkFact(question.getQuestionFact()); factCallback.onResult(result); } else if ("=>".equals(question.getOperator())) { List<Fact> results = deriveFacts(question.getQuestionFact()); impliantCallback.onResult(results); } else { throw new InvalidOperatorException("Unknown operator: " + question.getOperator()); } } // 可选:重载方法,只传对应类型的回调,避免无效参数 public void askFactCheck(Question question, FactCheckCallback callback) { if (!"?".equals(question.getOperator())) { throw new InvalidOperatorException("Expected operator '?' for fact check"); } callback.onResult(checkFact(question.getQuestionFact())); } public void askImpliantCheck(Question question, ImpliantCheckCallback callback) { if (!"=>".equals(question.getOperator())) { throw new InvalidOperatorException("Expected operator '=>' for impliant check"); } callback.onResult(deriveFacts(question.getQuestionFact())); } }
调用时,UI层只需传入对应的处理逻辑:
infoSet.ask(question, isTrue -> { // 处理事实校验的布尔结果 System.out.println("Fact is: " + isTrue); }, derivedFacts -> { // 处理推导的Fact列表 System.out.println("Derived facts: " + derivedFacts); } );
这个方案完全把类型判断逻辑放到后端,UI层只关注自身的处理逻辑,符合关注点分离原则。
方案3:使用密封类(Java 17+推荐方案)
如果你的项目使用Java 17或更高版本,可以利用**密封类(Sealed Classes)**定义不同的结果类型,ask()方法返回密封类实例,调用方用switch模式匹配处理,类型更安全,代码更简洁。
首先定义密封的结果接口:
// 密封类,只能被指定的子类继承 public sealed interface QueryResult permits FactCheckResult, ImpliantCheckResult { } // 事实校验结果(用record简化代码) public record FactCheckResult(boolean result) implements QueryResult { } // 推导校验结果(用record简化代码) public record ImpliantCheckResult(List<Fact> results) implements QueryResult { }
然后修改InformationSet的ask()方法:
public QueryResult ask(Question question) { if ("?".equals(question.getOperator())) { boolean result = checkFact(question.getQuestionFact()); return new FactCheckResult(result); } else if ("=>".equals(question.getOperator())) { List<Fact> results = deriveFacts(question.getQuestionFact()); return new ImpliantCheckResult(results); } else { throw new InvalidOperatorException("Unknown operator: " + question.getOperator()); } }
调用时,用switch模式匹配处理:
QueryResult result = infoSet.ask(question); // Java 17+的switch表达式,编译器会检查是否覆盖所有情况 var output = switch (result) { case FactCheckResult(boolean r) -> "Fact result: " + r; case ImpliantCheckResult(List<Fact> rs) -> "Derived facts count: " + rs.size(); }; System.out.println(output);
这个方案类型安全,编译器会确保你处理了所有可能的结果类型,避免遗漏,代码更现代优雅。
总结
- 若使用Java 17+,优先选密封类方案,类型安全且代码优雅;
- 若需要兼容旧版本Java,通用结果类方案是最稳妥的选择;
- 若希望完全解耦处理逻辑,回调模式会让UI层代码更简洁。
内容的提问来源于stack exchange,提问作者BRHSM
相关产品推荐
相关产品推荐

