访客模式:基于输入的数字算术

时间:2018-12-10 20:15:10

标签: c# design-patterns arithmetic-expressions visitor-pattern

假设我们在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...

我如何使用访问者模式对表达式求值并根据用户输入将结果写为intdouble?我以为我可以编写一个包含double result;的Visitor类,并且每个Visit(...)都将使用double算术来评估(sub)表达式,然后将结果转换为int需要。但这是使用访问者模式的最佳解决方案吗?如果以后我想使用long怎么办?是否有必要通过少量的代码来修改类,或者? (注意:我想使用访问者模式(而不是动态模式),而不要使用任何通用代码。)

1 个答案:

答案 0 :(得分:0)

我创建的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)