假设我有一个抽象类Drink,以及一个工厂方法,它选择在运行时创建的Drink(Wine,Beer等)类型。
每种饮料都需要一些参数来正确初始化自己。其中一些是所有饮料的共同点;例如,他们可能都需要DrinkConfig参数。
但每种饮料也可能有其独特的要求。也许Wine需要一个Sommelier辅助对象来初始化自己。啤酒不需要它,但它可能需要自己的辅助对象。
那么我应该将什么传递给工厂方法呢?当我调用它时,我有所有可用的辅助对象,所以我可以将它们全部传递给工厂。但这最终可能会引发很多争论。有没有更好的方法来设计它?
编辑:我们假设我不能在工厂中创建辅助对象;它们只能从来电者处获得。
答案 0 :(得分:4)
我会在你的工厂类中创建不同的重载方法。
public class DrinkFactory {
public static Drink CreateBeer(DrinkConfig config, string hops) {
return new Beer(config, hops);
}
public static Drink CreateWine(DrinkConfig config, string grapes, int temperature) {
return new Wine(config, grapes, temperature);
}
}
编辑:
如果希望在Factory类中只有一个方法,则替代实现将是:
public enum DrinksEnum {
Beer,
Wine
}
public class DrinkFactory {
public static Drink CreateDrink(DrinksEnum drinkType, DrinkConfig config) {
switch(drinkType) {
case DrinksEnum.Beer:
return new Beer(config);
case DrinksEnum.Wine:
return new Wine(config);
default:
throw new ApplicationException("Drink type not recognised.");
}
}
}
答案 1 :(得分:2)
工厂方法应该抽象出如何创建值的细节。因此,您不应该将辅助对象传递给工厂方法,工厂方法应该创建它需要的辅助对象并将其传递给相应的构造函数。
答案 2 :(得分:1)
工厂应该首先创建非常相似的对象。这意味着即使所有这些物品都是饮料,工厂方法可能也不合适,因为每种饮料与其他饮品差别很大。
说到这一点,你可以改为传递一个大小等于你想要设置的属性数量的对象列表。然后,每个对象将按照您要设置这些变量的顺序表示要在相应对象的构造函数中设置的值。这样做的缺点是你必须在打电话之前格式化工厂外的List,这有点笨拙。
答案 3 :(得分:0)
我很想提供一个天真的解决方案,你的成分来自基础类'DrinkIngredients'。您必须匹配用于特定饮品的子类。
显然,你可能想要为这些食材创造另一家工厂 - 但这会导致鸡蛋和鸡蛋问题。
答案 4 :(得分:0)
通常,存在隐藏这些细节的工厂方法。一个重要的问题是侍酒师来自哪里 - 如果所有这些其他帮助者都是单身人士或者可以从已知来源获得,那么将工厂实例化的必要信息去找他们,这样你的调用代码就不需要了担心它。
此外,在许多情况下,会使用诸如Spring之类的框架来允许您在配置文件中而不是在代码中描述这些关系。
如果你真的需要在运行时从调用代码传递助手,我建议阅读论文'参数和结果'(http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.50.7565),它描述了编组复杂参数的常用模式。基本上,您将创建必要参数的中间集合并将其传递给工厂。
答案 5 :(得分:0)
在这种情况下,我通常会寻找其他解决方案,而不是传递变量。
例如,在您的情况下 - WineFactory需要侍酒师,因此它可以构建适当的Wine -
这是运行时依赖注入的一个很好的用例。某种形式的依赖注入框架会使这非常简单,易于理解,而且只需要传递所有这些属性即可。
答案 6 :(得分:0)
这看起来像是Builder
模式的完美案例。使用Factory
模式创建类似对象,使用Builder
模式构建复杂,不相似的对象。尝试对此问题使用Factory
模式将导致不同对象的许多不同的初始化构造函数(具有不同数量/类型的参数)。