2011-12-15 78 views
1

我知道標題很奇怪,所以讓我試着做一些基本的設置。「嵌套」/組合策略模式?

我有一個叫做StyleBundle的對象。基於兩件事情,StyleBundle的持續時間和StyleBundle(Unlimited或PerStyle)的「類型」將決定StyleBundle的整體價格。所以,這裏快速剪下了StyleBundle:

public class StyleBundle 
{ 
    public decimal Price {get; set;} 
    public StyleType Type {get; set;} //STyleType is a simple enum, either "Unlimited" or "PerStyle" 
    public Duration Duration {get; set;} 
} 

這是持續時間。基本上,它有一個枚舉類型,是DurationType,它可以像DurationType.OneYear,DurationType.TwoYears等值...

public class Duration 
{ 
    public Duration(TimeSpan timeSpan, string name, DurationType type) 
    { 
     this.TimeSpan = timeSpan; 
     this.Name = name; 
     this.Type = type; 
    } 

    public TimeSpan TimeSpan { get; set; } 
    public string Name { get; set; } 
    public DurationType Type { get; set; } 
} 

在我StyleBundle類,我通過持續的戰略工廠叫StyleBundlePricingStrategy。下面是類:返回

public class StyleBundlePricingFactory 
{ 
    public static IPricingStrategy GetPricing(Duration duration) 
    { 
     if (duration.Type == DurationType.OneYear) { return new OneYearPricingStrategy(); } 
     if (duration.Type == DurationType.TwoYear) { return new TwoYearPricingStrategy(); } 
     etc... 
     etc... 
    } 
} 

類實現IPricingStrategy接口:

public interface IPricingStrategy 
{ 
    decimal GetPriceFor(StyleBundle aStyleBundle); 
} 

它得到的價格爲StyleBundle。每個策略類都封裝了給定DurationType的價格檢索方式。下面是OneYearPricingStrategy類的一個示例:

public class OneYearPricingStrategy : IPricingStrategy 
{ 
    public decimal GetPriceFor(StyleBundle aStyleBundle) 
    { 
     if (aStyleBundle.StylePricingType == StylePricingType.PerStyle) 
     { 
      return aStyleBundle.Products.Count() * 2500m; 
     } 
     else 
     { 
      return 50000m; 
     } 
    } 
} 

好吧,非常基本的策略設置。

是在吃了我的事情是,如果你看一下這行代碼中的「OneYearPricingStrategy」類:

if (aStyleBundle.StylePricingType == StylePricingType.PerStyle) 

,你會看到,我還是有使用條件的策略類以說明StyleBundle類型。 StyleBundle的類型將影響價格的計算方式。

對我來說,這是不好的設計,我寫的每個策略類的B/C「OneYearPricingStratety」,「TwoYearPricingStrategy」等... StylePricingType條件被複制並粘貼到所有的Strategy類。

這不好,b/c當我不得不添加一個新的StylePricingType時會發生什麼?我將不得不重新進入每個PricingStrategy類並更新代碼,所以將整個SRP排除在外(與其他事情一起)...

我需要的是一種實現某種類型模式的方法這將允許我結合兩個「stratagies」(持續時間與StyleBundleType),並允許規則生活在一個地方......不要在代碼中散佈。

當您爲一個策略實施時,很容易消化戰略模式,但這是兩個組合,而且我知道現在編寫它的方式不是一種好的做法,並且不能完成我想要它。

也許這是錯誤的模式?

任何指針將不勝感激。

謝謝, 邁克

編輯:

在反應亭子間的答案,我想提供我是如何走到擺在首位的策略模式的一些更詳細。我並沒有首先將實施策略強加於策略,但看到了我認爲的代碼味道,並決定策略模式可以幫助我。

最初,使用StyleBundle.Price屬性看起來像這樣:

public decimal Price 
{ 
    get 
    { 
     if (this.StylePricingType == StylePricingType.PerStyle) 
     { 
      if (this.Duration.Type == DurationType.ThreeDays) 
      { 
       _price = 1500m; 
      } 
      else if (this.Duration.Type == DurationType.OneYear) 
      { 
       _price = 2500m; 
      } 
      else if (this.Duration.Type == DurationType.TwoYears) 
      { 
       _price = 2000m; 
      } 
      else if (this.Duration.Type == DurationType.ThreeYears) 
      { 
       _price = 1650m; 
      } 
     } 
     else if (this.StylePricingType == StylePricingType.Unlimited) 
     { 
      if (this.Duration.Type == DurationType.ThreeDays) 
      { 
       throw new Exception("You can not have a StyleBundle of type Unlimited for a Duration of three days."); 
      } 
      else if (this.Duration.Type == DurationType.OneYear) 
      { 
       _price = 50000m; 
      } 
      else if (this.Duration.Type == DurationType.TwoYears) 
      { 
       _price = 40000m; 
      } 
      else if (this.Duration.Type == DurationType.ThreeYears) 
      { 
       _price = 33500m; 
      } 
     } 
     else 
     { 
      throw new Exception("Illegal StylePricingType passed to Product."); 
     } 
     return _price; 
    } 
    private set 
    { 
     _price = value; 
    } 
} 

我看到了任何時候,我會添加其他時間類型,我需要進入StyleBundle和更改代碼...到我認爲這似乎是激勵原則,足以尋求更好的解決方案。現在

,與戰略設計模式這個問題的應用程序,我StyleBundle.Price屬性看起來是這樣的:

public decimal Price 
    { 
     get 
     { 
      return _pricingStrategy.GetPriceFor(this); 
     } 
     private set 
     { 
      _price = value; 
     } 
    } 

其中_pricingStrategy是IPricingStrategy,並決定其實現者了新的決定通過在StyleBundle的構造函數中調用StyleBundlePricingFactory.GetPricing(duration)類。

回答

3

在編寫代碼之前,不要試圖考慮模式。代碼然後重構。偶爾你會重構成一個模式。

策略模式通常保留用於當您要委派類的行爲邏輯。例如,如果我有ChessPlayer類,那麼Grandmaster implements ChessStrategyNovice implements ChessStrategy將是改變我的ChessPlayer的行爲策略的好方法,而ChessPlayer移動棋子的界面不必更改。

就你而言,你只需要有數據,而不是複雜的價格計算策略,所以我會尋找合適的數據結構。雙重嵌套HashMap超過持續時間X PricingStyles會正常工作。例如:

Price calculatePrice(Duration d, PricingStyle s) { 
    return map.get(d).get(s); 
} 

PS:當涉及到良好的設計,任何需要更少的代碼通常是贏家。

+0

Garret,請參閱我的編輯。我最初的代碼是「臭」,這裏策略模式的應用似乎對我有意義。 – 2011-12-15 20:21:56