使用冗长计算的类 - 减少开销

时间:2014-08-20 15:55:09

标签: c# .net vb.net class oop

假设我有一个具有多个属性的类,这些属性是基于计算的,甚至可以依赖于共享类成员的存在......像这样说这样的例子:

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

在整个代码中可以多次调用实例化对象,因此我不想每次都重新计算这些值,,同时,我还想考虑代码中某些属性可能已经改变的可能性,因此,应该重新运行这些方法......

我正在考虑使用以下两种方式来做这件事:

  1. 对于每种方法,创建一个私有布尔值(如_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
    
  2. 我看到有诸如INotifyPropertyChanged接口之类的东西,但似乎是通知当前对象以外的对象,而且实现起来似乎很昂贵。

  3. 有没有标准/正确的方法来做到这一点?或者最好考虑哪种方法/模式?

    另外,即使提供的源代码是VB,我也同样熟悉VB / C#解决方案。

    感谢!!!

2 个答案:

答案 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;
    }
}