2011-12-15 14 views
1

私はタイトルが奇妙であることを知っているので、私はいくつかの基本的なセットアップをやろうとしましょう。「入れ子にされた」/組み合わされた戦略パターン?

私はStyleBundleというオブジェクトを持っています。 StyleBundleのDurationとStyleBundle(UnlimitedまたはPerStyle)の「type」の2つに基づいて、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;} 
} 

ここではDurationです。基本的に、それは私がStyleBundlePricingStrategyと呼ばれる戦略工場への所要時間を渡す、などDurationType.OneYear、DurationType.TwoYears、のような値であることができDurationTypeで列挙型、...私のStyleBundleクラスで

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のための価格を取得します

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

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インタフェースを実装し返されます。各戦略クラスは、所与の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のタイプは、価格の計算方法に影響します。

私にとって、これは "OneYearPricingStratety"、 "TwoYearPricingStrategy"などと書かれた各戦略クラスのb/cです。StylePricingType条件はすべての戦略クラスにコピーされて貼り付けられます。

これはうまくいきません。b/c新しいStylePricingTypeを追加する必要がある場合はどうなりますか?私は各PricingStrategyクラスに戻ってコードを更新しなければならないので、SRP全体が(他のものと一緒に)ウィンドウの外に出る必要があります...

私は必要なものは、ある種のパターンを実装する方法ですこれは2つの "ストラテジー"(DurationとStyleBundleType)を組み合わせて、ルールを1つの場所に置くことを可能にします。コード間に絡み合わないようにします。

ストラテジを実装するときにSTrategyパターンを消化するのは簡単ですが、これは2つの組み合わせであり、今書いたとおりの方法を知っています。それが欲しい。

多分それは間違ったパターンですか?

すべてのポインタは高く評価されます。

おかげで、 マイク

EDIT:ギャレットの答えに反応して

は、私が最初の場所での戦略パターンになった方法についていくつかの詳細を提供したいです。最初にストラテジーに実装したのではなく、コードの匂いと思っていたものを見て、戦略パターンが私を助けることができると決めました。

当初、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プロパティは次のようになります。

_pricingStrategyはIPricingStrategyで、最大新への実装の決定が決定され
public decimal Price 
    { 
     get 
     { 
      return _pricingStrategy.GetPriceFor(this); 
     } 
     private set 
     { 
      _price = value; 
     } 
    } 

StyleBundleのコンストラクターでStyleBundlePricingFactory.GetPricing(duration)クラスを呼び出すことによってオンにできます。

答えて

3

コードを書く前にパターンを考えないでください。リファクタリングしてコード化する。時折、あなたはパターンにリファクタリングします。

ストラテジーパターンは、通常、クラスのビヘイビアロジックを委任するときに予約されます。たとえば、私がクラスChessPlayerを持っている場合、Grandmaster implements ChessStrategyNovice implements ChessStrategyは、ChessPlayerの行動戦略を変更する良い方法です。ChessPlayerのインタフェースは、変更する必要はありません。

あなたのケースでは、複雑な価格計算戦略ではなく、単にデータがあるので、適切なデータ構造を探します。 Duration X PricingStylesを二重に入れ子にしたHashMapはうまく動作します。例:

PS:良いデザインになると、少ないコードであれば勝者となります。

+0

ガレット、私の編集を参照してください。私の最初のコードは「臭い」でしたが、ここで戦略パターンを適用することは意味があるようでした。 –

+0

さて、私の更新答えをご覧ください。 –

関連する問題