我之前曾问过this问题。这与它有关。我们有类似的代码库:
IRecipie FindRecipiesYouCanMake(IEnumerable<Ingredientes> stuff, Cook cook)
{
if(stuff.Any(s=>s.Eggs && s.Flour) && cook.DinerCook)
{
if(s=>s.Sugar)
return new Pancake("Yum");
if(s=>s.Salt)
return new Omlette("Yay");
}
/*.....
......
.....
loads of ifs and buts and else*/
}
我想摆脱这种混乱,采取更多的数据结构和OO路线。即使我提供的代码示例也不像它那样可怕。我查看了规范模式,发现它适用。任何想法如何改进代码。
编辑:现在我意识到了,我甚至可能想要实现这种签名的方法:
List<IRecipe> WhatAllCanBeCooked(IEnumerable<Ingredients> stuff, Cook cook);
答案 0 :(得分:3)
我会将这个逻辑委托给各个IRecipie类:
if (Pancake.CanBeMadeBy(stuff, cook)) {
return new Pancake("Yum");
}
....
public class Pancake: IRecipe {
...
public static bool CanBeMadeBy(IEnumerable<Ingredientes> stuff, Cook cook) {
return stuff.Any(s=>s.Eggs && s.Flour && s.Sugar) && cook.DinerCook;
}
}
编辑以回复评论
要查找可以烹饪的所有食谱,只需执行以下操作:
List<IRecipe> results = new List<IRecipe>();
if (Pancake.CanBeMadeBy(stuff, cook)) {
results.Add(new Pancake("Yum");
}
....
编辑2
或者,如果您在某处存储了所有可能配方的列表,则可以将CanBeMadeBy
转换为实例方法而不是静态方法,并执行以下操作:
List<IRecipe> allRecipes = // all possible recipes
...
return allRecipes.Where(r => r.CanBeMadeBy(stuff, cook));
答案 1 :(得分:1)
一些想法:
使用strategy pattern。这有助于您将一组属于一起的操作或参数封装在不同的具体类中。一旦您决定使用哪种策略,您就不再需要任何“ifs”来分配策略。
编辑:一些额外的想法:
开始“小”:大多数情况下,只需简单地重构到较小的,名称很好的可重用函数,就可以帮助你减少if-else-if-else-soup。有时,一个简单,命名良好的布尔变量可以解决这个问题。这两个都是您在Fowler's book "Refactoring"中找到的重构示例。
认为“大”:如果你有很多复杂的业务规则,构建“特定于域的语言”是一种有时可能是降低复杂性的正确方法。你可以通过谷歌搜索找到很多关于这个主题的资料。引用David Wheeler 计算机科学中的所有问题都可以通过另一层次的间接解决。
答案 2 :(得分:1)
ORIGIINAL POST - Martin Fowler已经为你解决了这个问题......它被称为规范模式 http://en.wikipedia.org/wiki/Specification_pattern
更新帖子 -
在以下情况下考虑使用复合规格模式:
模式的真正力量在于能够将不同的规范组合成具有AND,OR和NOT关系的复合材料。将不同规格组合在一起可以在设计时或运行时完成。
Eric Evan关于领域驱动设计的书籍就是这种模式的一个很好的例子(航运清单)这是Wiki链接:
http://en.wikipedia.org/wiki/Specification_pattern
在wiki链接的底部是这个PDF链接:
答案 3 :(得分:0)
我认为该代码块实际上要完成的是将配方链接到该配方中的成分。一种方法是在配方类本身中包含一系列成分,然后将其与传入的成分列表进行比较,如下所示:
public interface IRecipe {
IEnumerable<Ingredient> Ingredients { get; }
}
public class Omlette : IRecipe {
public IEnumerable<Ingredient> Ingredients {
get {
return new Ingredient[]{new Ingredient("Salt"), new Ingredient("Egg")};
}
}
}
// etc. for your other classes.
IRecipie FindRecipiesYouCanMake(IEnumerable<Ingredientes> stuff, Cook cook)
{
var query = Recipes.Where(r => !r.Ingredients.Except(stuff).Any());
return query.First();
}
这假设您的所有食谱中都有一个集合。然而,设置静态列表或从数据库中提取它应该很简单。
有问题的Linq查询查找任何食谱,其中所有成分传递的成分都存在于成分列表中(或者,如上所述,成分中没有成分中没有成分)。这也可能减少了为Recipes设置子类的需要,这看起来有点奇怪(尽管我知道还有其他原因你需要这个)