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

+1 Randolpho와 LBushkin 모두.

그러나 나는 그것에 대해 약간의 생각을했으며이 냄새의 이유를 알고 있다고 생각합니다. 필자가 구현 한 패턴은 빌더 패턴의 일종의 변형 일 것 같습니다. 더 잘 작동하는 것은 일련의 분석 단계에서 합성물을 만드는 것이고, 전체적으로 볼 때 의미있는 상태를 나타냅니다. 분석 프로세스 (동작)의 각 단계는 출력 Composite (상태)와 구별되어야합니다. 위에서 구현 한 것은 상태와 동작을 함께 메시징합니다. 상태 보유자와 상태 분석기가 하나의 동일한 객체이기 때문에 이는 단일 책임 원칙에도 위배됩니다. 위의 프로토 타입이 결정적으로 완료 되었더라도 합성 "자체 빌드"방식은 악의적 인 루프를 만들 가능성을 열어줍니다.

링크 :

Builder Pattern

Composite Pattern

1

여기에 가장 큰 잠재적 인 문제는 Sweep 방법은 잠재적으로 Widget.DoMyThing()에 대한 호출에서 변경 될 수 있습니다 모음 (_tiers) 반복된다는 점이다 : 여기

은 샘플 구현입니다.

.NET BCL 클래스는 컬렉션이 반복되는 동안 변경되지 않도록합니다. 이 코드는 구조화 된 방식으로 이러한 일이 발생할 수있는 위험이 있습니다.

그 외에도 프로그램의 구조가 어떤 순서로 발생하는지 이해하기 어렵게 만드는 문제가 있습니다. 아마도 모델을 재 방문하여 계산을 수행하는 부분에서 모델을 재귀 적으로 어셈블 링하는 프로그램의 단계를 분리 할 수 ​​있습니다.

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

가 변경 될 때 당신은 컬렉션을 반복됩니다

+0

'의 반복되는 것으로 변경하지 않습니다 _tiers'; 'Widget.DoMyThing()'을 호출 할 때마다 * wid * teir에 위젯이 추가됩니다. – Randolpho

2

예, 나는 다음과 같은 코드 냄새를 호출합니다. 첫 번째 반복을 의미하며 두 번째 반복은 의미하지 않습니다. 당신은 분명히 변화를 설명하고 있습니다 (그러므로 foreach이 아닌 < _tierCount). 그러나 여전히 IMO입니다.

생산 코드로 보내 줄 수 있습니까? 혹시. 시나리오에 따라 다릅니다. 그러나 나는 그것에 대해 더러워 질 것입니다.

또한 _tiers 회원은 List<List<Widget>> 일 수 있습니다.

관련 문제