提问人:simondx 提问时间:7/7/2023 最后编辑:simondx 更新时间:7/7/2023 访问量:82
解决方法参数中的 Java 接口歧义
Resolve Java Interface ambiguity in method parameters
问:
我有一个布尔运算树,来自一个布尔表达式,我必须在 Java 中运行。树是这样的: 我需要在 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 中做到这一点(我尝试使用一些泛型或抽象类,但没有工作),或者更好的是解决这个问题的正确方法(我们有一个写成二叉树的二进制表达式,我们想通过调用与每个节点关联的类来解决它)?
答:
你可能把这个问题搞得太复杂了。如果想要一个像图像中所示的表达式树,请创建一个表达式树。您无需区分“运算符”和“输入”。
// 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();
如果你真的想分离出 / 节点的“输入”,你可以。只是概括为IsNumberOdd
IsNumberEven
BooleanExpression
Expression<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();
评论
T
LogicOperator
LogicOperator
PropertyChecking
And.fire()
left.fire()
left
LogicOperator
fire()
Ti
fire()
T
Ti
And
Or