这对于 OO 语言来说是完美的,因为引用的工作方式。在抽象层面上,我会这样处理:
创建一个抽象类 ,Expression
它将成为我们程序中所有值的基类型。就像是:
public abstract class Expression
{
List<Expression> linkedExpressions;
protected Expression lhs; // left hand side, right hand side
protected Expression rhs;
protected Expression(Expression x, Expression y)
{
List<Expression> linkedExpressions = new List<Expression>();
lhs = x;
rhs = y;
// let the expressions know that they have a expression dependant on them
lhs.NotifyExpressionLinked(this);
rhs.NotifyExpressionLinked(this);
}
private void NotifyExpressionLinked(Expression e)
{
if (e != null)
{
linkedExpressions.Add(e);
}
}
private void NotifyExpressionUnlinked(Expression e)
{
if (linkedExpressions.Contains(e)
{
linkedExpressions.Remove(e);
}
}
// this method will notify all subscribed expressions that
// one of the values they are dependant on has changed
private void NotifyExpressionChanged()
{
if (linkedExpressions.Count != 0) // if we're not a leaf node
{
foreach (Expression e in linkedExpressions)
{
e.NotifyExpressionChanged();
}
}
else Evaluate()
// once we're at a point where there are no dependant expressions
// to notify we can start evaluating
}
// if we only want to update the lhs, y will be null, and vice versa
public sealed void UpdateValues(Expression x, Expression y)
{
if (x != null)
{
lhs.NotifyExpressionUnlinked(this);
x.NotifyExpressionLinked(this);
lhs = x;
}
if (y != null)
{
rhs.NotifyExpressionUnlinked(this);
y.NotifyExpressionLinked(this);
rhs = y;
}
NotifyExpressionChanged();
}
public virtual float Evaluate()
{
throw new NotImplementedException(); // we expect child classes to implement this
}
}
为我们需要的每种表达式类型创建一个类。在最底部,您将有一个LiteralExpression
,它只是一个数字:
public class LiteralExpression : Expression
{
private float value;
public LiteralExpression(float x)
: base(null, null) { } // should not have any linked expressions
public override float Evaluate()
{
return value;
}
}
关于这个类需要注意的一点 - 由于它的工作方式,不应在其上使用 UpdateValue()。相反,只需创建一个新的 LiteralExpression 来替换它。
然后,您需要为您想要的所有表达式构建子类(例如,这里是添加):
public class AdditionExpression : Expression
{
public AdditionExpression(Expression x, Expression y)
: base(x, y) { };
public override float Evaluate()
{
return lhs.Evaluate() + rhs.Evaluate();
}
}
不是我们必须为每个表达式编写的所有代码——所有繁重的工作都由抽象类处理。这个程序有一些设计缺陷——它不会检测循环引用,也不会阻止你将null
值传递给表达式(在 LiteralExpression 的情况下是必需的),但这些问题应该不会太难修理。
然后,需要做的就是实现所有从表达式继承的子类。
可能有更好的方法来做到这一点,但从 OO 的角度来看,这是一个很好的例子,它创建了一个实现常见行为的通用抽象类,并为该类的每个“风格”提供了许多小的、特定的实现。