2010-03-29 59 views
2

我現在玩的想法是擁有一個多級分析對象的「層級」系統,該系統對一個通用對象執行特定計算,然後根據其結果創建一組新的分析對象。新創建的分析對象將自行運行並可選擇創建更多分析對象,等等。問題的關鍵是孩子的分析對象將始終在創建它們的對象之後執行,這是相對重要的。整個設備將被單線程調用,所以我現在不關心線程安全性。只要滿足一定的基本條件,我並不認爲這是一個不穩定的設計,但我仍然對它有點不安。帶分析小工具的分層設計 - 此代碼是否有氣味?

這是一些嚴重的代碼味道,還是應該繼續實施它?有沒有更好的辦法?

下面是一個簡單的實現:

namespace WidgetTier 
{ 
    public class Widget 
    { 
     private string _name; 

     public string Name 
     { 
      get { return _name; } 
     } 

     private TierManager _tm; 
     private static readonly Random random = new Random(); 

     static Widget() 
     { 
     } 

     public Widget(string name, TierManager tm) 
     { 
      _name = name; 
      _tm = tm; 
     } 

     public void DoMyThing() 
     { 
      if (random.Next(1000) > 1) 
      { 
       _tm.Add(); 
      } 
     } 
    } 

    //NOT thread-safe! 
    public class TierManager 
    { 
     private Dictionary<int, List<Widget>> _tiers; 
     private int _tierCount = 0; 
     private int _currentTier = -1; 
     private int _childCount = 0; 

     public TierManager() 
     { 
      _tiers = new Dictionary<int, List<Widget>>(); 
     } 

     public void Add() 
     { 
      if (_currentTier + 1 >= _tierCount) 
      { 
       _tierCount++; 
       _tiers.Add(_currentTier + 1, new List<Widget>()); 
      } 
      _tiers[_currentTier + 1].Add(new Widget(string.Format("({0})", _childCount), this)); 
      _childCount++; 
     } 

     //Dangerous? 
     public void Sweep() 
     { 
      _currentTier = 0; 
      while (_currentTier < _tierCount) //_tierCount will start at 1 but keep increasing because child objects will keep adding more tiers. 
      { 
       foreach (Widget w in _tiers[_currentTier]) 
       { 
        w.DoMyThing(); 
       } 
       _currentTier++; 
      } 
     } 

     public void PrintAll() 
     { 
      for (int t = 0; t < _tierCount; t++) 
      { 
       Console.Write("Tier #{0}: ", t); 
       foreach (Widget w in _tiers[t]) 
       { 
        Console.Write(w.Name + " "); 
       } 
       Console.WriteLine(); 
      } 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      TierManager tm = new TierManager(); 

      for (int c = 0; c < 10; c++) 
      { 
       tm.Add(); //create base widgets; 
      } 

      tm.Sweep(); 
      tm.PrintAll(); 

      Console.ReadLine(); 
     } 
    } 
} 

回答

0

對Randolpho和LBushkin都+1。

但是,我給了它一些想法,我想我知道爲什麼這個味道。我已經實現的模式似乎是對Builder模式的某種顛倒。更好的工作是從一系列分析步驟中創建一個綜合體,這些步驟總體上代表某種有意義的狀態。分析過程(行爲)的每一步應該與輸出複合(狀態)不同。我上面實現的是將狀態和行爲一起網格化。由於國有人和國家分析人員是同一個對象,這也違反了單一責任原則。即使我上面的原型具有確定性的完成,但使用「自己構建」組合的方法開闢了創建惡性循環的可能性。

鏈接:

Builder Pattern

Composite Pattern

1

這裏最大的潛在問題是Sweep方法遍歷集合(_tiers),可以在呼叫可能更改爲Widget.DoMyThing()

.NET BCL類不允許集合在迭代時更改。代碼的結構方式暴露出這種情況可能發生的風險。

除此之外,另一個問題是程序的結構使得很難理解以什麼順序發生的事情。也許你可以將程序的階段從遞歸地組裝模型的那一部分和訪問模型並執行計算的部分區分開來。

+0

'_tiers'作爲其正在迭代不會改變;每次調用'Widget.DoMyThing()'都會向* next * teir添加一個'Widget'。 – Randolpho 2010-03-29 21:36:44

2

是的,我把下面的代碼氣味:

 _currentTier = 0; 
     while (_currentTier < _tierCount) //_tierCount will start at 1 but keep increasing because child objects will keep adding more tiers. 
     { 
      foreach (Widget w in _tiers[_currentTier]) 
      { 
       w.DoMyThing(); 
      } 
      _currentTier++; 
     } 

您遍歷集合,因爲它正在發生變化。我的意思是第一次迭代,而不是第二次。您顯然會考慮這種變化(因此< _tierCount而不是標準foreach),但它仍然是一種氣味,IMO。

我會讓它進入產品代碼嗎?有可能。取決於場景。但我會覺得很骯髒。

另外:您的_tiers會員可能很容易成爲List<List<Widget>>