访问者模式:基于输入的数字运算
Visitor pattern: Number arithmetics based on input
假设我们在 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
?我想我可能会写一个包含 double result;
的访问者 class,每个 Visit(...)
将使用 double
算术计算(子)表达式,然后我将结果转换为 int
如果需要的话。但这是使用访问者模式的最佳解决方案吗?如果我以后想使用 long
怎么办?有必要通过大量代码修改 classes,或者? (注意:我想使用访客模式(而不是动态模式)而不是任何通用代码。)
而不是 int Evaluate()
我创建了 void Accept(IExpressionVisitor visitor)
函数。 PlusExpression
class 现在看起来像这样:
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)
。
假设我们在 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
?我想我可能会写一个包含 double result;
的访问者 class,每个 Visit(...)
将使用 double
算术计算(子)表达式,然后我将结果转换为 int
如果需要的话。但这是使用访问者模式的最佳解决方案吗?如果我以后想使用 long
怎么办?有必要通过大量代码修改 classes,或者? (注意:我想使用访客模式(而不是动态模式)而不是任何通用代码。)
而不是 int Evaluate()
我创建了 void Accept(IExpressionVisitor visitor)
函数。 PlusExpression
class 现在看起来像这样:
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)
。