我正在研究配方应用程序的域模型并遇到问题。
该应用程序有多个实体可以作为一种成分,其中两个是:Product
和Recipe
(食谱可以是其他食谱中的成分)。通常我会将与成分相关的功能封装到每个实体都可以实现的接口中。问题在于,虽然所有产品实例都可以是成分,但只有一部分食谱实例可以成为。
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
}
}
如何重新构建此模型以支持只有某些配方实例应该能够作为成分的要求?
答案 0 :(得分:2)
听起来像是一个设计问题。如果你必须开始为IsIngredient进行测试,我认为你的设计出了问题。如果您有其他特殊情况,会发生什么?然后是另一个?你是否会继续添加特殊的If测试或大的switch语句?这违反了开放原则。
如何支持组合而不是继承?您可能还想查看策略模式...
这里的核心问题是Recipe不应该实现IIngredient ...因为并非所有食谱都实现了IIngredient行为......
答案 1 :(得分: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
}
}
答案 2 :(得分: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
}
}
}
答案 3 :(得分:0)
我可能会使用合成来创建一个可以组合2个(可能更多)食谱的CompositeRecipe
。没有能够将所有配方用作新食谱的基础的原因是什么?您总是可以向建议添加一个布尔属性,该配方是一个完整的配方(IsCompleteRecipe
),然后由您构建应用程序和应用程序逻辑来决定是否食谱应该与其他人结合。
答案 4 :(得分:0)
如果只有一些食谱是成分,那么它似乎是继承的经典案例,在子类上实现了IIngredient
:
class Product : IIngredient
{
void DoIngredientStuff();
}
class Recipe
{
public IEnumerable<IIngredient> Ingredients { get; set; }
}
class IngredientRecipe : Recipe, IIngredient
{
void DoIngredientStuff();
}
答案 5 :(得分:-1)
您可以使用adaptor使配方表现为一种成分:
class RecipeIngredient : IIngredient
{
private readonly Recipe _recipe;
public RecipeIngredient(Recipe recipe) {
_recipe = recipe;
}
public void DoIngredientStuff() {
// Do stuff with the recipe.
}
}