分析小部件的分层设计 - 此代码是否有气味?

时间:2010-03-29 21:23:52

标签: c# .net algorithm collections

我现在正在玩的想法是拥有一个多层次的“层级”分析对象系统,它对公共对象执行某种计算,然后根据其结果创建一组新的分析对象。然后,新创建的分析对象将自行运行并可选择创建更多分析对象,依此类推。关键是子分析对象将始终在创建它们的对象之后执行,这是相对重要的。整个设备将由一个线程调用,所以我现在不关心线程安全。只要满足某个基本条件,我不认为这是一个不稳定的设计,但我仍然有点不安。

这是一些严重的代码味道还是我应该继续以这种方式实现它?还有更好的方法吗?

以下是一个示例实现:

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

3 个答案:

答案 0 :(得分: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>>

答案 1 :(得分:1)

这里最大的潜在问题是Sweep方法正在迭代一个集合(_tiers),该集合可能会在调用Widget.DoMyThing()时发生变化。

.NET BCL类不允许在迭代时更改集合。代码的结构方式暴露了这可能发生的风险。

除此之外,另一个问题是程序的结构使得很难理解以什么顺序发生的事情。也许您可以将递归组装模型的程序阶段与访问模型并执行计算的部分分开。

答案 2 :(得分:0)

+1 Randolpho和LBushkin。

然而,我给了它一些想法,我想我知道为什么这闻起来。我实现的模式似乎是对Builder模式的某种歪曲。更好的方法是从一系列分析步骤中创建一个复合词,从整体上看,它代表某种有意义的状态。分析过程(行为)的每一步都应与输出Composite(状态)不同。我上面实现的内容将状态和行为结合在一起。由于国家持有者和国家分析者是同一个对象,这也违反了单一责任原则。复合“构建本身”的方法开辟了创建恶性循环的可能性,即使我的上述原型具有确定性完成。

链接:

Builder Pattern

Composite Pattern