解决方法参数中的 Java 接口歧义

Resolve Java Interface ambiguity in method parameters

提问人:simondx 提问时间:7/7/2023 最后编辑:simondx 更新时间:7/7/2023 访问量:82

问:

我有一个布尔运算树,来自一个布尔表达式,我必须在 Java 中运行。树是这样的: The problem 我需要在 Java 中迭代运行它,以便它返回一个布尔值。

boolean b = AND(isNumberEven("4"), AND(isNumberOdd("7"), isNumberEven("6"))

问题是我需要编写接口,因为在我的公司中,我们可以创建许多类,例如 And、Or、isSomething、hasInArray(它可以是其他开发人员需要的任何属性)。我们通常有两种类型的节点:逻辑节点,它有两个分支,以及属性检查节点,它们是树的叶子。

我在下面尝试做的事情是我认为在 Java 中确实错误的事情,请帮助我正确地做到这一点。

我的想法是创建两个接口,一个用于逻辑运算符,另一个用于属性检查。属性检查器需要从输入中评估其属性,而逻辑运算符需要评估两个分支,然后用两个结果计算一些东西(比如 AND 或 OR,我们暂时不关心 NOT 运算符)。我正在考虑做这些接口

class PropertyCheckingInput {
   String s; // dummy property, this object is the thing we want to verify the property on (example, if this string is an even number)

   PropertyCheckingInput(...){...} // constructor for all params
}

interface PropertyChecking {
   boolean fire(PropertyCheckingInput i);
}

class LogicOperatorInput<
   T extends LogicOperator or PropertyChecking, // it can be one or the other
   Ti extends LogicOperatorInput or PropertyCheckingInput
> {
    T left;
    Ti leftInput;
    T right;
    Ti rightInput;

    // probabily the type of leftInput should act accordingly to the type of left, but I don't know how to enforce this in Java with generics

    LogicOperatorInput(...){...} // constructor for all params
}

interface LogicOperator{
   boolean fire(LogicOperatorInput i); 
}

在这种情况下,如果我想实现类似 AND 的东西,我可以像这样做

class And implements LogicOperator {
    boolean fire(LogicOperatorInput i) {
        i.left.fire(i.leftInput) && i.right.fire(i.rightInput);
    }

    And() {}

    public static void main(String[] args) {
        // expression: isNumberEven("4") AND isNumberOdd("7") AND isNumberEven("6")
        boolean b = new And().fire(new LogicOperatorInput(
            new isNumberEven(), 
            new PropertyCheckingInput("4"), 
            new And(), 
            new LogicOperatorInput(
                new isNumberOdd(), 
                new PropertyCheckingInput("7"), 
                new isNumberEven(), 
                new PropertyCheckingInput("6"))
        ));

        System.out.println(b);
    }
}

对于每个分支,我都会使用它们的输入执行左右函数 fire,并且只关心它们的结果。然后,如果我想创建一个布尔表达式,我将各种节点和输入连接起来。

编译器当然告诉我这是错误的,因为它无法推断出 fire( ) 函数的正确类型。

我习惯于用 Javascript 编写,它允许这种类型的东西,因为它不会检查你要做什么。有没有办法在 Java 中做到这一点(我尝试使用一些泛型或抽象类,但没有工作),或者更好的是解决这个问题的正确方法(我们有一个写成二叉树的二进制表达式,我们想通过调用与每个节点关联的类来解决它)?

Java 泛型 推理逻辑 运算符 表达式

评论

0赞 jtahlborn 7/7/2023
好吧,你的核心问题是你试图说 in 是 a 或 .然后在 your 中,您尝试使用单个参数进行调用。但是,如果 是 ,则该方法接受 4 个参数,而不是 1。我不能说我完全理解你想做什么,但也许这会有所帮助?TLogicOperatorLogicOperatorPropertyCheckingAnd.fire()left.fire()leftLogicOperatorfire()
0赞 meriton 7/7/2023
我也不明白你想做什么,所以很难帮助你。你说你想要一个表达式树,但你的用法示例既不创建也不使用树,它只是调用一些函数,并将它们返回的布尔值提供给 add 函数,该函数返回一个布尔值。那棵树在哪里?
0赞 daniu 7/7/2023
您的示例主要是什么 A、B 和 C?我不明白为什么逻辑运算符应该接受四个参数。
0赞 Andrew S 7/7/2023
作为参数似乎有点尴尬(破坏封装)。似乎它将是一个可以包装实际和的接口(或者可能是一个适配器)。然后,可以接受可变数量的参数,并委托给包装器/适配器。Tifire()TTiAndOr
0赞 simondx 7/7/2023
很抱歉造成混乱,我试图重写示例

答:

1赞 Sweeper 7/7/2023 #1

你可能把这个问题搞得太复杂了。如果想要一个像图像中所示的表达式树,请创建一个表达式树。您无需区分“运算符”和“输入”。

// this represents a tree "node"
interface BooleanExpression {
    // all nodes should implement this to represent how they are evaluated
    boolean evaluate();
}

// a node can be any of these types
record IsNumberEven(int number) implements BooleanExpression {
    @Override
    public boolean evaluate() {
        return number() % 2 == 0;
    }
}

record IsNumberOdd(int number) implements BooleanExpression {
    @Override
    public boolean evaluate() {
        return number() % 2 == 1;
    }
}

record And(BooleanExpression left, BooleanExpression right) implements BooleanExpression {
    @Override
    public boolean evaluate() {
        return left().evaluate() && right().evaluate();
    }
}

用法:

boolean result = new And(
        new IsNumberEven(4),
        new And(
                new IsNumberOdd(7),
                new IsNumberEven(6)
        )
).evaluate();

如果你真的想分离出 / 节点的“输入”,你可以。只是概括为IsNumberOddIsNumberEvenBooleanExpressionExpression<T>

interface Expression<T> {
    T evaluate();
}

record Constant<T>(T value) implements Expression<T> {
    @Override
    public T evaluate() {
        return value();
    }
}

record IsNumberEven(Expression<Integer> number) implements Expression<Boolean> {
    @Override
    public Boolean evaluate() {
        return number().evaluate() % 2 == 0;
    }
}

record IsNumberOdd(Expression<Integer> number) implements Expression<Boolean> {
    @Override
    public Boolean evaluate() {
        return number().evaluate() % 2 == 1;
    }
}

record And(Expression<Boolean> left, Expression<Boolean> right) implements Expression<Boolean> {
    @Override
    public Boolean evaluate() {
        return left().evaluate() && right().evaluate();
    }
}

用法:

boolean result = new And(
        new IsNumberEven(new Constant<>(4)),
        new And(
                new IsNumberOdd(new Constant<>(7)),
                new IsNumberEven(new Constant<>(6))
        )
).evaluate();

评论

0赞 simondx 7/7/2023
我没有考虑在方法之外添加输入。谢谢!