从特定的表达式树到通用的表达式树-Java

时间:2018-12-16 19:24:05

标签: java generics

我想编写一个抽象类'Expression',它接受整数或布尔表达式,并通过诸如'Add','Divide'作为整数和'And','Or'作为布尔表达式的子类对它们进行求值。最后,归结为编写实现其自己的validate()方法的子类。我在一本书中找到了一个实现,但它仅适用于double值。在这里:

abstract class Expr {
    abstract double eval();
}
abstract class BinOp extends Expr {
    Expr left;
    Expr right;
    BinOp(Expr l, Expr r) {
    }
}
class Const extends Expr {
    private double value;
    Const( double val ) {
        this.value = val;
    }
    double eval () {
        return this.value;
    }//eval
}

现在,对于BinOp类,我可以编写一个类'Add'对其进行扩展,调用它的构造函数,并使用2个Const对象的乘积实现eval(),这些对象本身是eval()并简单地返回它们实例化的值用。

如果我想使用Expr来做这项工作,而Expr并不严格将其计算为double,而是int或boolean?我已经阅读了泛型,但似乎无法正确设计Expr这样的类来编译我的代码。这是我的尝试:

public abstract class Expression<T> {
    abstract T evaluate();
}
public class Const<T> extends Expression{
    private T n;
    public Const(T x) { n = x; }
    public Const<Integer> integerConst(Integer n) {
        return new Const<>(n);
    }
    public Const<Boolean> booleanConstConst(Boolean n) {
        return new Const<>(n);
    }
    public T evaluate() {
        return n;
    }
}

现在,我不希望任何人为我做功课,所以我只是问我的方法的错误在哪里,是否有人可以指出我正确的方向。谢谢。

2 个答案:

答案 0 :(得分:1)

以下是一些建议:

  • 首先,您不应该使用原始类型,因此Const<T>应该扩展Expression<T>

  • 现在,您的integerConstbooleanConstConst方法看起来像工厂方法,因此应该是static

  • 也就是说,我不确定在Const类中包含这些工厂方法是否是一个好主意,因为如果您愿意,它将迫使您更改Const类型支持第三种表达式类型(除了BooleanInteger之外)。相反,您可能要考虑子类Const

    public class IntegerConst extends Const<Integer> {
        public IntegerConst(Integer n) {
            super(n);
        }
    }
    
    public class BooleanConst extends Const<Boolean> {
        public BooleanConst(Boolean b) {
            super(b);
        }
    }
    

希望您可以从这里继续。

答案 1 :(得分:0)

我认为您应该将所有逻辑隐藏在Expression后面,并且所有类型特定的逻辑都应放在单独的类中。

要隐藏具体的实现,您应该为每个具体的实现使用参数化的Expression类和工厂方法

public interface Expression<T> {

    T evaluate();

    static BooleanExpression with(boolean val) {
        return new BooleanExpression(val);
    }

    static DoubleExpression with(double val) {
        return new DoubleExpression(val);
    }

}

使用必需的运算符实现“布尔”值:

public final class BooleanExpression implements Expression<Boolean> {

    private final boolean left;

    public BooleanExpression(boolean left) {
        this.left = left;
    }

    public BooleanExpression and(boolean right) {
        return new BooleanExpression(left && right);
    }

    public BooleanExpression or(boolean right) {
        return new BooleanExpression(left || right);
    }

    @Override
    public Boolean evaluate() {
        return left;
    }
}

使用必需的运算符对integer值的实现(我使用double,因为您应该实现divide):

public final class DoubleExpression implements Expression<Double> {

    private final double left;

    public DoubleExpression(double left) {
        this.left = left;
    }

    public DoubleExpression add(double right) {
        return new DoubleExpression(left + right);
    }

    public DoubleExpression divide(double right) {
        return new DoubleExpression(left / right);
    }

    @Override
    public Double evaluate() {
        return left;
    }
}

客户端代码向您显示所有具体的实现均已隐藏,并且每个表达式只有可接受的运算符:

boolean res1 = Expression.with(false).and(true).or(true).evaluate();   // true
double res2 = Expression.with(0.5).add(2.5).divide(2).evaluate();       // 1.5