我有一个表示包含许多计算属性的域实体的类。大多数计算依赖于也计算的其他属性。在它最简单的形式中,类的示例可能看起来像这样。
public class AnalysisEntity
{
public decimal InputA { get; set; }
public decimal InputB { get; set; }
public decimal InputC { get; set; }
public decimal CalculatedValueA
{
get { return InputA * InputC; }
}
public decimal CalculatedValueB
{
get
{
decimal factor = FactorGenerator.ExpensiveOperation();
return CalculatedValueA / factor;
}
}
public decimal CalculatedValueC
{
get { return InputA * InputB; }
}
public decimal CalculatedValueD
{
get { return (CalculatedValueA * InputB) / CalculatedValueB; }
}
public decimal CalculatedValueE
{
get { return CalculatedValueD / aConstant; }
}
}
然而,这个解决方案给我留下了以下问题:
我已经尝试过使用计算器对象和策略模式来设置属性的内部字段,但我最终会得到一个过长的控制函数来强制进行计算。同时将所有计算移动到另一个对象会将原始实体变为贫血域对象,我应该避免阅读。
我应该使用哪些设计模式和类结构来解决上述问题?
由于
答案 0 :(得分:5)
在写入路径上执行工作,而不是读取路径。然后,您可以从持久层填充最新的缓存值,而无需担心。
因此,当写入值A时,所有依赖于A的计算都将重做。
这种方案在读取次数大于写入次数的情况下效果很好。
答案 1 :(得分:1)
缓存是一个好主意 - 如果它可能有很多缓存命中率。
每次初始化setter时都会避免重新计算,因为对象可能还没有处于一致状态(例如,如果在设置其余部分之前分配InputA,新对象会发生什么?)
尝试计算属性之间的依赖关系可能非常困难,并且可能很快失控,使对象处于不一致状态。我将输出与输出分开并具有显式操作来计算状态。 例如,让对象具有只读属性。然后使用输入数据生成另一个对象,并将其作为参数传递给“CalculateState”方法。 (可选)根据具体情况,使对象不可变并将输入传递给构造函数。在具有明确定义的输入的单个位置进行计算将有助于测试。课程计算可以分解,设计模式应用等。
答案 2 :(得分:0)
James提出了一个很好的观点,主要是使用预先计算来最小化检索时间内的低效率。
当然,这需要您在更改类中的值时了解相关属性。我会考虑为其他人所依赖的属性实现INotifyPropertyChanged
或IObservable<T>
接口,这将是Observer/Observable或发布/订阅设计模式。
答案 3 :(得分:0)
为避免重复计算,您可以按照计算任何值的模式,如果相关变量发生变化,可以通过使用状态变量来实现:
public class AnalysisEntity
{
private decimal _ca;
private decimal _cb;
private decimal _cc;
private bool calculate_a = false;
private bool calculate_b = false;
private bool calculate_c = false;
private bool calculate_d = false;
private bool calculate_e = false;
public decimal InputA { get { return a;} set { a=value; calculate_a = true; calculate_c = true; } }
public decimal InputB { get { return b;} set { b=value; calculate_c = true; calculate_d = true; } }
public decimal InputC { get { return c;} set { c=value; calculate_a = true; } }
public decimal CalculatedValueA
{
get
{
if( calculate_a ) { _ca = InputA * InputC; calculate_a = false; calculate_b = true; }
return _ca;
}
}
public decimal CalculatedValueB
{
get
{
if( calculate_b ) { _cb = (CalculatedValueA / FactorGenerator.ExpensiveOperation()); calculate_b = false; calculate_d = true; }
return _cb;
}
}
public decimal CalculatedValueC
{
get
{
if( calculate_c ) { _cc = InputA * InputB; calculate_c = false; }
return _cc;
}
}
public decimal CalculatedValueD
{
get
{
if( calculate_d ) { _cd = (CalculatedValueA * InputB) / CalculatedValueB; calculate_d = false; calculate_e = true; }
return _cd;
}
}
public decimal CalculatedValueE
{
get
{
if( calculate_e ) { _ce = CalculatedValueD / aConstant; calculate_e = false; }
return _ce;
}
}
}