2011-12-15 56 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