2012-04-25 22 views
3

私は、レシピアプリケーションのドメインモデルで作業中で、問題にぶつかっています。特定の動作を特定のクラスのインスタンスのサブセットに限定する方法はありますか?

このアプリケーションには、成分として作用することができる複数の実体があり、そのうちの2つは、ProductRecipeです(レシピは他のレシピの成分にすることができます)。通常は、これらのエンティティのそれぞれが実装できるインタフェースに、コンポーネント関連の機能をカプセル化します。問題は、すべての製品インスタンスが成分になることができますが、レシピインスタンスのサブセットのみが成分になることができます。私はいくつかのレシピインスタンスが成分として作用することが可能でなければならない要件をサポートするために、このモデルを再構築するにはどうすればよい

interface IIngredient 
{ 
    void DoIngredientStuff(); 
} 

class Product : IIngredient 
{ 
    void DoIngredientStuff() 
    { 
     // all Products are ingredients - do ingredient stuff at will 
    } 
} 

class Recipe : IIngredient 
{ 
    public IEnumerable<IIngredient> Ingredients { get; set; } 

    void DoIngredientStuff() 
    { 
     // not all Recipes are ingredients - this might be an illegal call 
    } 
} 

+2

は素敵な答えを見つけ出すために、私たちは、「なぜ、正確にすべてのレシピを理解する必要があります材料として作用する –

答えて

2

別のオプションあなたのクラスツリーでこれらの2つのタイプのレシピについて別々のクラスを持つように動作する場合。オブジェクトを区別するプロパティがさらにある場合、この方法はうまくいかないことに注意してください。

class Recipe { 
    public IEnumerable<IIngredient> Ingredients { get; set; } 

} 

class UsefulRecipe : Recipe, IIngredient 
{ 
    void DoIngredientStuff() 
    { 
     // not all Recipes are ingredients - this might be an illegal call 
    } 
} 
+0

SmartRecipe、UsefulRecipe、RecipeWithOnlyFiveInstructions、RecipeThatCanBeOnlyFiveYearsOld、MyGrandmasHalfHundredYearOldRecipeOfExtraTastyPancakesThatWeAteLastNewYearEve –

+0

は、私は私の答えに書き込もうとしましたが、それは二行目にあったと...あなたがそれを言うためのより良い方法を持っている場合は答えを編集すること自由に感じなさい。 –

1
interface IIngredient 
{ 
    bool IsIngredient { get; } 
    void DoIngredientStuff(); 
} 

class Recipe : IIngredient 
{ 
    public IEnumerable<IIngredient> Ingredients { get; set; } 

    bool IsIngredient { 
     get { return true; // true if it is, false if it isn't } 
    } 

    void DoIngredientStuff() 
    { 
     if (IsIngredient) { 
     // do whatever 
     } 
    } 
} 
+0

これはうまくいくかもしれませんが、欠陥があり、伸びがないデザインです。新しい特殊条件をデザインに追加する必要があるたびに、リファクタが必要になります。 – MrLane

+1

私はそれが欠陥があるとは思わない。これは、.NET System.IO.Streamライブラリで使用されるアプローチです。いくつかのストリームは読み込みをサポートしていますが、そうでないものもあります。これはブール値のプロパティで伝えられます。あなたのケースでは、いくつかのレシピは食材であり、いくつかのレシピはそれを表現する最も簡単な方法の1つです。さらに、これらのエンティティを永続化する場合は、各レシピでビットフィールドを格納して、それを成分として使用できるかどうかを示すことを選択するのではなく、多態的なアプローチを回避する方が簡単です。 – eulerfx

+0

これは欠陥があります。最小の驚きの原則に違反する(http://en.wikipedia.org/wiki/Principle_of_least_astonishment)。それが成分の場合、DoIngredientStuffにできる必要があります。さもなければ、それを強制するインターフェースのポイントは何ですか? –

2

私には設計上の問題があります。 IsIngredientのテストを開始する必要がある場合は、設計に間違いがあったと思います。別の特別な症例があるとどうなりますか?そしてもう1つは?特別なIfテストや大きなswitch文を追加し続けるつもりですか?それはオープンクローズの原則を破ります。

継承を超える構成を優先するにはどうすればよいですか?あなたが本当にここで問題の核心は、そのレシピがIIngredientを実装すべきではないです...また、Strategyパターンを見て

をお勧めします...ないすべてのレシピIIngredient動作を実装起こす...

-1

あなたは成分として振る舞うレシピを作るためにadaptorを使用することができます。

class RecipeIngredient : IIngredient 
{ 
    private readonly Recipe _recipe; 

    public RecipeIngredient(Recipe recipe) { 
     _recipe = recipe; 
    } 

    public void DoIngredientStuff() { 
     // Do stuff with the recipe. 
    } 
} 
+0

私はアダプターはあなたが適応可能なものを制御できないときにのみ使うべきだと思います –

+0

私はそれがこの状況で使うのに適したパターンだと思います。レシピは、それらが成分であるかどうかを知る必要はなく、必要に応じて任意のレシピを成分とすることができます。どのように問題にアプローチしますか? –

0

私はおそらく2(多分それ以上)のレシピを組み合わせることができCompositeRecipeを作成するために組成物を使用します。すべてのレシピを新しいレシピのベースとして使用できないという理由は何ですか?ブール値プロパティをに追加すると、レシピが完全レシピ(IsCompleteRecipe)であることがわかります。次に、レシピを他のものと組み合わせる必要があるかどうかを判断するアプリケーションロジックとアプリケーションロジックの作成方法までです。 IIngredient

+0

レシピを作成しても、すべてのレシピが成分ではないという問題は修正されません。 –

0

のみいくつかのレシピの成分である場合、それは、相続のための古典的なケースだが、サブクラスに実装されている:

class Product : IIngredient 
{ 
    void DoIngredientStuff(); 
} 

class Recipe 
{ 
    public IEnumerable<IIngredient> Ingredients { get; set; } 
} 

class IngredientRecipe : Recipe, IIngredient 
{ 
    void DoIngredientStuff(); 
} 
+0

成分のレシピではなく、成分として機能するレシピについてです。大きな違いがあります。 –

+0

このデザインでは、IngredientRecipeはまさにそれです:a原料として機能することができるレシピ。私は「食材のレシピ」が何であるか理解していません。 – Dan

+0

私はどちらか分かりません。あいまいな名前ですあなたはそれを成分として作用することができる特殊なレシピとして見ます、私はそれを原料のレシピとして見ます。とにかく - あなたの答えはhttp://stackoverflow.com/a/10325249/82062と同じです –

関連する問題