Шаблон посетителя: Числовая арифметика, основанная на вводе - PullRequest
0 голосов
/ 10 декабря 2018

Допустим, у нас есть следующая иерархия данных в C # для оценки математических (префиксных) выражений в int арифметике:

abstract class Expression {
        public abstract int Evaluate();
}

class ValueExpression : Expression {
    public int Value {
        get;
    }

    public sealed override int Evaluate() {
        return Value;
    }
}

abstract class OperatorExpression : Expression {
    // ...
}

abstract class BinaryExpression : OperatorExpression {
    protected Expression op0, op1;

    public Expression Op0 {
        get { return op0; }
        set { op0 = value; }
    }

    public Expression Op1 {
        get { return op1; }
        set { op1 = value; }
    }

    public sealed override int Evaluate() {
        return Evaluate(op0.Evaluate(), op1.Evaluate());
    }

    protected abstract int Evaluate(int op0Value, int op1Value);
}

sealed class PlusExpression : BinaryExpression {
    protected override int Evaluate(int op0Value, int op1Value) {
        return checked(op0Value + op1Value);
    }
} // and more operators...

Как я могу использовать шаблон посетителя для оценки выражения и выписатьрезультат как int или double на основе ввода пользователя?Я подумал, что мог бы написать класс Visitor, который содержит double result;, и каждый Visit(...) будет оценивать (под) выражение, используя double арифметику, а затем я преобразую результат в int, если это необходимо.Но является ли это лучшим решением для этого с помощью шаблона посетителя?Что если я захочу использовать long позже?Надо было бы модифицировать классы нетривиальным количеством кода, или?(Примечание: я хотел бы использовать шаблон посетителя (а не динамический), а не какой-либо общий код.)

1 Ответ

0 голосов
/ 12 декабря 2018

Вместо int Evaluate() я создал void Accept(IExpressionVisitor visitor) функцию.Класс PlusExpression теперь выглядел так:

sealed class PlusExpression : BinaryExpression
{
    public override void Accept(IExpressionVisitor visitor)
    {
        visitor.Visit(this);
    }
}

Затем я создал двух посетителей, происходящих из IExpressionVisitor.Например, посетитель для целочисленной арифметики выглядит следующим образом:

class ExpressionIntVisitor : IExpressionVisitor
{
    Stack<int> stack = new Stack<int>();

    public int GetRetVal()
    {
        return stack.Peek();
    }

    public void Visit(LiteralExpression exp)
    {
        stack.Push(exp.Value);
    }

    public void Visit(PlusExpression exp)
    {
        exp.Op0.Accept(this);
        exp.Op1.Accept(this);
        int b = stack.Pop();
        int a = stack.Pop();

        stack.Push(checked(a + b));
    }

Примечание: Stack на самом деле не является необходимым, поскольку он содержит не более 2 значений.

Для двойной арифметики этопочти то же самое.Теперь мы называем Accept(intVisitor) или Accept(doubleVisitor) в зависимости от того, что нам нужно.

...