2010-10-26 83 views
4

我有一個類表示一個包含許多計算屬性的域實體。大部分計算取決於也計算的其他屬性。最簡單的形式是類的例子可以看起來像這樣。類中相關計算屬性的設計模式?

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

然而,這種解決方案將離開我解決以下問題:

  1. 正是在一些計算(其中一些是長時間)的低效率越來越一再呼籲。
  2. 要單獨測試單個計算而不提供所有必需的輸入,以使所有依賴計算首先工作,這是很困難的。
  3. 這是很難從持久有效地檢索(我使用NHibernate的),因爲即使計算出的數據可以存儲到數據庫中,它不會檢索,每當對象被讀取,而不是重新計算。
  4. 隨着單元測試隨着所需輸入變得越來越大,很難增加計算。

我已經嘗試過使用計算器對象和策略模式來設置屬性的內部字段,但我最後得到了一個過長的控制函數來強制執行計算。另外將所有計算轉移到另一個對象將原始實體轉變爲我不斷閱讀的貧血域對象應該避免。

我應該使用什麼設計模式和類結構來解決上述問題?

謝謝

回答

5

在寫入路徑而不是讀取路徑上工作。然後,您可以從持久層填充最新的緩存值,而不必擔心。

所以,當值A被寫入,這取決於所有的計算都重做。其中讀取次數超過寫入次數大於

此方案的偉大工程。

+0

謝謝詹姆斯,我可以看到如何工作。 – 2010-10-27 00:31:30

0

詹姆斯一個好點的,基本上是使用預先計算,以儘量減少在檢索時間的低效率。

當然,這需要你知道相關的屬性,當您更改類的值。我會考慮實現INotifyPropertyChangedIObservable<T>接口的其他人依賴的屬性,這將是Observer/Observable或發佈/訂閱設計模式。 - 如果有可能

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; 
     } 
    } 
} 
+0

感謝您的模式,我一定會給IObservable 一個去。 – 2010-10-27 00:34:43

0

爲了避免重複計算就可以了,跟着計算任何價值的模式,如果相關的變量發生變化,它可以通過使用狀態變量來實現有大量的緩存命中。

我會避免,因爲每個對象可能不是一致的狀態還沒有一個設置初始化時間重新計算(例如會發生一個新的對象是什麼,如果你曾經設置的其他部分之前分配InputA?)

試圖找出屬性之間的依賴關係可能非常困難,並且可能很快失控,導致對象處於不一致狀態。我會將輸入與輸出分開,並有明確的操作來計算狀態。例如,讓對象具有隻讀屬性。然後用輸入數據創建另一個對象,並將其作爲參數傳遞給「CalculateState」方法。或者,根據具體情況,使對象不可變並將輸入傳遞給構造函數。在具有明確輸入的單個地點進行計算將有助於測試。當然可以分解計算,設計模式應用等

1

緩存是一個好主意: