假设我有一个具有多个属性的类,这些属性是基于计算的,甚至可以依赖于共享类成员的存在......像这样说这样的例子:
Public Class FakeClass
Public Shared Property Needed As FakeObject
Public Property Prop1 as Double
Public Property Prop2 as Double
Public Function Func1() As Double
' Lengthy calculation using some properties, etc
End Function
Public Function Func2() As Double
' Lengthy calculation involving <Func1>, some properties, etc
End Function
Public Function Func3() As Double
' Lengthy calculation involving <Func1> and needing <Needed>
End Function
End Class
在整个代码中可以多次调用实例化对象,因此我不想每次都重新计算这些值,但,同时,我还想考虑代码中某些属性可能已经改变的可能性,因此,应该重新运行这些方法......
我正在考虑使用以下两种方式来做这件事:
对于每种方法,创建一个私有布尔值(如_RecalcFunc1
)和一个私有Double(例如_Func1Val
)以使最终方法看起来像:
Private _RecalcFunc1 As Boolean = True
Private _Func1Val As Double
Public Function Func1() As Double
If _RecalcFunc1 Then
_Func1Val = ' Lengthy calculation
_RecalcFunc1 = False
End If
Return _Func1Val
End Function
和
Public Shared Property Needed As FakeObject = Nothing
Public Function Func3() As Double
If Needed Is Nothing Then
Throw New InvalidOperationException("The ""Needed"" object is necessary to perform this calculation.")
End If
' Lengthy calculation involving <Func1> and needing <Needed>
End Function
我看到有诸如INotifyPropertyChanged
接口之类的东西,但似乎是通知当前对象以外的对象,而且实现起来似乎很昂贵。
有没有标准/正确的方法来做到这一点?或者最好考虑哪种方法/模式?
另外,即使提供的源代码是VB,我也同样熟悉VB / C#解决方案。
感谢!!!
答案 0 :(得分:1)
听起来您的计算值比它们所依赖的值被更频繁地读取。在这种情况下,您可以为依赖值创建一个实际的实例字段,并在它们所依赖的任何值的setter中重新计算它们。
也可能值得考虑使这种类型不可变,而不是可变,尽管与前一个选项不同,这将是一个重大的突破性变化。使类不可变意味着您可以在构造对象时始终急切地计算派生值,而不必担心这些缓存值变得陈旧。然后,您可以在值需要更改时重新创建整个对象的新实例。假设这些值并没有经常改变,那么这可能是更可取的。
答案 1 :(得分:1)
您应该为每个函数创建一个变量,然后该函数应该只返回与该函数对应的变量。然后在属性setter方法中,您应该调用一个私有的重新计算方法来进行冗长的计算并将其保存到变量中。
以下是显示我的意思的代码:
public class FakeClass
{
private double func1Result;
private double func2Result;
private double func3Result;
public FakeClass()
{
func1Result = Double.MinValue;
func2Result = Double.MinValue;
func3Result = Double.MinValue;
_property1 = Double.MinValue;
_property2 = Double.MinValue;
_neededObject = null;
}
private double _property1;
public double Property1
{
get { return _property1; }
set
{
if (_property1 != value)
{
_property1 = value;
RecalculateFunc1Result();
}
}
}
private double _property2;
public double Property2
{
get { return _property2; }
set
{
if (_property2 != value)
{
_property2 = value;
RecalculateFunc2Result();
}
}
}
private static FakeObject _neededObject;
public FakeObject Needed
{
get { return _neededObject; }
set
{
if (_neededObject != value)
{
_neededObject = value;
RecalculateFunc3Result();
}
}
}
private double RecalculateFunc1Result()
{
// Check to make sure the values are not the default/invalid ones.
if (_property1 == Double.MinValue ||
_property2 == Double.MinValue)
{
func1Result = Double.MinValue;
return func1Result;
}
//func1Result = Lengthy calculation involing some properties.
return func1Result;
}
private double RecalculateFunc2Result()
{
// Check to make sure the values are not the default/invalid ones.
if (_property1 == Double.MinValue ||
_property2 == Double.MinValue)
{
func2Result = Double.MinValue;
return func2Result;
}
//func2Result = Lengthy calculation involing some properties and
// RecalculateFunc1Result() or func1Result.
return func2Result;
}
private double RecalculateFunc3Result()
{
if (Needed == null)
throw new InvalidOperationException(
@"The ""Needed"" object is necessary to perform this calculation.");
//func3Result = Lengthy calculation involving RecalculateFunc1Result()
// or func1Result
return func3Result;
}
}