如何解决如何将类设计为可通过两种不同的方式扩展?
我正在开始使用OOP,但我有一个关于在这种情况下如何正确设计类的问题:
想象一下我想创建一个代数库。我会将任何表达式表示为一棵树,每个节点要么是叶变量或常量,要么是父操作,例如+或^。
我也希望能够以许多不同的方式来评估该表达式。我想允许使用不同的方法将表达式评估为浮点数,整数或有理数等,因为每种评估方法都有不同的优缺点。
这意味着我有两种可能的库潜在用户想要扩展我的表达式类的方式-添加新的节点类型(即新操作)或添加新的评估方法。
为允许添加新的节点类型,我将使用继承-我可以使用抽象基类来表示表达式,然后库的用户可以简单地重写此类来创建新操作:
abstract class Expression
{
public abstract float Evaluate();
}
class Addition : Expression
{
Expression a;
Expression b;
public override float Evaluate()
{
return a.Evaluate() + b.Evaluate();
}
}
etc...
但是为了允许添加新的评估方法,我将使用一个单独的评估类将评估方法移出Expression类:
abstract class Expression
{
public abstract float Evaluate();
}
class Addition : Expression
{
Expression a;
Expression b;
}
abstract class ExpressionEvaluator<T>
{
public abstract T Evaluate(Expression e);
}
class FloatExpressionEvaluator : ExpressionEvaluator<float>
{
public override float Evaluate(Expression e)
{
switch (e)
{
case Addition addition:
return Evaluate(addition.a) + Evaluate(addition.b);
etc...
}
}
}
但是此方法不允许添加其他操作。感觉好像很容易出错,因为没有编译时检查是否所有类在Evaluate方法中都有大小写。
有没有一种方法可以使表达式类在两个方向上都可以扩展,并通过编译时检查确保所有表达式都可以在所有评估方法中使用?
解决方法
有很多方法,但是由于您需要通用方法,因此我建议您使用MiscUtil
,它是一个具有通用运算符(加,减..etc)的通用库。您可以在代码中使用它,它将为您简化事情。
对于运算符,由于它们的功能是一对一的,因此无需为每个运算符创建一个类。例如,Addition
类将仅包含加法运算符(a + b)。没有复杂的数学运算。因此,我建议对这些运算符使用method
。并专注于主班。根据需要,主类可以包含许多运算符。有些很简单(如加,减等),有些则很复杂。对于简单的运算符,请保持简单,而对于复杂的运算符,您可能需要为它们实现一些类以简化它们。
对于实现设计本身,我认为Fluent API在您的情况下会更有利。因此,想象一下库的用法将是这样的:
// would result 30 (as double).
var result =
new ExpressionOperator<double>(15.5)
.Add(15)
.Subtract(0.5)
.Evaluate();
可以这样实现(使用MiscUtil
lib):
public sealed class ExpressionOperator<T> where T : struct
{
private T _result;
public ExpressionOperator(T a)
{
_result = a;
}
public ExpressionOperator<T> Add(T b)
{
_result = Operator.Add(_result,b);
return this;
}
public ExpressionOperator<T> Subtract(T b)
{
_result = Operator.Subtract(_result,b);
return this;
}
public T Evaluate() => _result;
public static explicit operator T(ExpressionOperator<T> exp) => exp._result;
}
然后,这取决于您如何使用它并对其进行扩展以满足您的需求。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。