samedi 18 avril 2020

Expression evaluation using visitor pattern

I have been trying to design an expression evaluator using visitor framework. Before going into my current design here are few problems that I am facing.

  1. Current design works well with arithmetic operators but when it comes to logical operators for eg 5 > 6 will output to false it doesn't work. As Visitor is a generic interface so if I say Visitor<Boolean> the return value will become boolean but participating values are integer hence I am not able to have integer as parameter.
  2. The design requires a class for every operator can it be minimized?
  3. Please share your inputs on design. Does it look good or any modification needed.

Following are participating classes.

Here is visitor interface

public interface Visitor<T> {

    T visit(Expression expression);

    T visit(BinaryExpression binaryExpression);

    T visit(ConstantExpression expression);
}

visitor implementation

public class ExpressionVisitor<T> implements Visitor<T> {

    @Override
    public T visit(Expression expression) {
        return expression.accept(this);
    }

    @Override
    public T visit(BinaryExpression arithmeticExpression) {
        Operator op = arithmeticExpression.getOperator();
        T left = visit(arithmeticExpression.getLeft());
        T right = visit(arithmeticExpression.getRight());
        return op.apply(left, right);
    }

    @Override
    public T visit(ConstantExpression expression) {
        return (T) expression.getValue();
    }
}

A class which represents expression

public abstract class Expression {

    public abstract  <T>  T accept(Visitor<T> visitor);
}

Class for binary expression

public class BinaryExpression extends Expression {

    private Operator operator;
    private Expression left;
    private Expression right;

  //constructor and getters

    @Override public <T> T accept(Visitor<T> visitor) {
        return visitor.visit(this);
    }
}

A class that represents Constant value

public class ConstantExpression extends Expression {


    private Object value;

//constructor and getter

    @Override public <T> T accept(Visitor<T> visitor) {
        return visitor.visit(this);
    }
}

Operator clas

public abstract class Operator {

    public <T> T apply(T left, T right) {
        try {
            Method method = this.getClass().getMethod("do" + left.getClass().getSimpleName() + this.getClass().getSimpleName(), left.getClass(), right.getClass());
            method.setAccessible(true);
            return (T) method.invoke(this, left, right);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
           throw new RuntimeException("Failed");
        }
    }
}

And Addition operator

public class Addition extends Operator {


    public Integer doIntegerAddition(Integer left, Integer right) {
        return left + right;
    }

    public Double doDoubleAddition(Double left, Double right) {
        return left + right;
    }

    public String doStringAddition(String left, String right) {
        return left + right;
    }
}

Aucun commentaire:

Enregistrer un commentaire