采用以下经典工厂模式:
public interface IPizza
{
decimal Price { get; }
}
public class HamAndMushroomPizza : IPizza
{
decimal IPizza.Price
{
get
{
return 8.5m;
}
}
}
public abstract class PizzaFactory
{
public abstract IPizza CreatePizza(ItalianPizzaFactory.PizzaType pizzaType);
}
public class ItalianPizzaFactory : PizzaFactory
{
public enum PizzaType
{
HamMushroom,
Deluxe,
Hawaiian
}
public override IPizza CreatePizza(PizzaType pizzaType)
{
switch (pizzaType)
{
case PizzaType.HamMushroom:
return new HamAndMushroomPizza();
case PizzaType.Hawaiian:
return new HawaiianPizza();
default:
throw new ArgumentException("The pizza type " + pizzaType + " is not recognized.");
}
}
}
如果一个(或多个)混凝土比萨饼需要特定于施工中具体实施的参数,该怎么办?例如,假设HamAndMushroom工厂需要一个名为MushroomType的参数,并且需要此参数来实例化对象?
答案 0 :(得分:19)
您可以将参数添加到工厂的创建者方法中。但是,如果参数的数量越来越多(对我而言,这将超过2-3),特别是如果这些参数中的部分或全部是可选的,并且具有合理的默认值,您可以考虑将工厂变为{{3相反。
这可能特别适合比萨饼,在那里你通常有相同的外壳,只有不同的(组合)浇头。 Builder非常接近于常见的排序方式,例如“萨拉米香肠,西红柿,玉米和双层奶酪的比萨饼”。 OTOH用于“预定义”比萨,您可能想要定义辅助工厂方法,例如createMargaritaPizza
或createHawaiiPizza
然后在内部使用构建器创建披萨,其中包含特定于此类披萨的浇头。
答案 1 :(得分:1)
您可以传递一个新参数,例如Map。并查询每个具体构造函数的属性。然后所有方法都具有相同的签名。 但是,使用此解决方案,构造函数的调用者必须知道concret构造函数的特定属性...(耦合)
答案 2 :(得分:0)
您必须为该工厂类添加另一个CreatePizza()方法。这意味着工厂的用户将无法创建这些类型的比萨,除非他们专门使用HamAndMushroomPizzaFactory类的实例。如果他们只是有一个PizzaFactory引用,他们只能调用无参数版本,并且无法一般地创建火腿和蘑菇比萨饼。
答案 3 :(得分:0)
您可以使用反射:
using System.Reflection;
// ...
public override IPizza CreatePizza(PizzaType pizzaType, params object[] parameters) {
return (IPizza)
Activator.CreateInstance(
Assembly
.GetExecutingAssembly()
.GetType(pizzaType.ToString()),
parameters);
}
答案 4 :(得分:0)
首先,我觉得抽象类PizzaFactory
包含一个抽象的通用方法CreatePizza
,它采用更具体的类型{{1}的参数,这似乎很奇怪。 }}
为了解决我刚刚提到的问题以及帖子中提到的问题,我建议采用以下方法。
ItalianPizzaFactory.PizzaType
如您所见,ParseTag()方法可能具有任意复杂性,解析纯文本或加密值。或者Tag字段可以是一个简单的int,它在内部映射到一些披萨配方表,其中包含完全不同的配方,甚至可以略微更改披萨内容。
答案 5 :(得分:0)
您可以尝试这样的事情:
interface IPizza
{
}
class Pizza1 : IPizza
{
public Pizza1(Pizza1Parameter p)
{
}
}
class Pizza2 : IPizza
{
public Pizza2(Pizza2Parameter p)
{
}
}
interface IPizzaParameter
{
object Type { get; set; }
}
class Pizza1Parameter : IPizzaParameter
{
public object Type { get; set; }
}
class Pizza2Parameter : IPizzaParameter
{
public object Type { get; set; }
}
static class PizzaFactory
{
public enum PizzaType
{
Pizza1,
Pizza2,
}
public static IPizza CreatePizza(PizzaType type, IPizzaParameter param)
{
switch (type)
{
case PizzaType.Pizza1:
return new Pizza1(param as Pizza1Parameter);
case PizzaType.Pizza2:
return new Pizza2(param as Pizza2Parameter);
}
throw new ArgumentException();
}
}
class Program
{
static void Main()
{
var param1 = new Pizza1Parameter();
var p1 = PizzaFactory.CreatePizza(PizzaFactory.PizzaType.Pizza1, param1);
}
}
具有实现特定参数的工厂的IMHO概念看起来不对。
答案 6 :(得分:0)
当参数计数变得非常高时,我认为工厂变得不那么方便和冗余,因为它的主要观点是使创建过程看不见。
此外,当参数是“必需的”时,我也认为Builder失去了它的魅力。
在这种情况下,我可能希望将工厂与“参数对象”结合起来,这将减少传递给静态工厂方法所需的参数数量,这可能使创建逻辑比使用生成器。但是,当然也需要创建该参数对象,但至少它应该是整个应用程序中的单个形式。