2010-03-29 53 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>>