我知道标题很奇怪,所以让我试着做一些基本的设置。“嵌套”/组合策略模式?
我有一个叫做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)类。
Garret,请参阅我的编辑。我最初的代码是“臭”,这里策略模式的应用似乎对我有意义。 – 2011-12-15 20:21:56