工厂模式但带有对象参数
采用以下经典工厂模式:
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 的参数,并且需要此参数来实例化该对象吗?
Take the following classic factory pattern:
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.");
}
}
}
What if one (or many) of the Concrete Pizzas requires a parameter specific to the concrete implementation at construction. For example, lets say the HamAndMushroom factory requires a parameter called, MushroomType and this parameter would be required to instantiate the object?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您可以将参数添加到工厂的创建者方法中。但是,如果参数数量越来越多(对我来说会超过 2-3 个),特别是如果这些参数中的部分或全部是可选的,并且具有合理的默认值,您可以考虑将工厂变成 Builder。
这可能特别适合披萨,通常有相同的外壳,只是有不同的配料(组合)。 Builder 非常接近常见的订购方式,例如“带有萨拉米香肠、西红柿、玉米和双层奶酪的披萨”。 OTOH 对于“预定义”披萨,您可能需要定义辅助工厂方法,例如
createMargaritaPizza
或createHawaiiPizza
,然后在内部使用构建器创建具有特定于该类型的配料的披萨披萨。You can add parameters to the creator method(s) of your factory. However, if the number of parameters is getting higher (for me that would be more than 2-3), and especially if some or all of those parameters are optional with reasonable default values, you may consider turning the factory into a Builder instead.
That may be especially appropriate for pizzas, where you usually have the same crust, just with different (combinations) of toppings. A Builder models very closely the common way of ordering e.g. "a pizza with salami, tomatoes, maize and double cheese". OTOH for "predefined" pizzas you may want to define helper factory methods, e.g.
createMargaritaPizza
orcreateHawaiiPizza
which then internally use the builder to create a pizza with the toppings specific to that kind of pizza.您必须为该工厂类添加另一个 CreatePizza() 方法。这意味着工厂的用户将无法创建这些类型的披萨,除非他们专门使用 HamAndMushroomPizzaFactory 类的实例。如果他们只有 PizzaFactory 引用,则只能调用无参数版本,并且无法创建一般的火腿和蘑菇披萨。
You would have to add another CreatePizza() method for that factory class. And that would mean that users of the factory wouldn't be able to create those types of pizzas unless they were specifically using an instance of the HamAndMushroomPizzaFactory class. If they simply have a PizzaFactory reference, they can only call the parameterless version and won't be able to create ham and mushroom pizzas generically.
您可以传递一个新参数,例如 Map。并查询每个具体构造函数的属性。那么所有的方法都会有相同的签名。
然而,通过这个解决方案,构造函数的调用者必须知道具体构造函数的具体属性......(耦合)
You could pass a new parameter, such as a Map. And query the properties on each concrete constructor. Then all the methods would have the same signature.
However, with this solution, the caller of the constructor has to know the specific properties of the concret constructor...(Coupling)
您可以尝试这样的操作:
恕我直言,具有特定于实现的参数的工厂概念看起来是错误的。
You can try something like this:
IMHO concept of factory with implementation specific parameters looks wrong.
当参数数量变得非常高时,我确实认为工厂变得不那么方便和多余,因为它的主要目的是使创建过程变得不可见。
另外,当参数是“必需的”时,我也认为 Builder 失去了它的魅力。
在这种情况下,我可能希望将工厂与“参数对象”结合起来,这将减少需要传递到静态工厂方法中的参数数量,并且可以使创建逻辑比使用生成器更具可读性和简洁性。当然,还需要创建该参数对象,但至少它会在您的应用程序中以一种单一形式存在。
When parameter count gets very high, I do think factory becomes less handy and redundant since the main point of it to make the creation process kinf of invisible.
Also, when the parameters are 'required', then I also think Builder loses its charm.
In this case, I may want to combine factory with a 'Parameter Object' which would reduce the # of parameters needed to be passed into the static factory methods and that could have made the creation logic more readable and neat than using a Builder. But of course, that parameter object is also needed to be created as well but at least it would be in one, single form across your application.
首先,我觉得奇怪的是,抽象类
PizzaFactory
包含一个抽象通用方法CreatePizza
,它采用更具体类型的参数ItalianPizzaFactory.PizzaType
。为了解决我刚才提到的问题和帖子中提到的问题,我建议采用以下方法。
如您所见,ParseTag() 方法可以具有任意复杂性,解析纯文本或加密值。或者,Tag 字段可以是一个简单的 int,它在内部映射到某个披萨食谱表,即使披萨内容略有变化,也可以使用完全不同的食谱。
First of all, it seems strange to me that an abstract class
PizzaFactory
contains an abstract general methodCreatePizza
that takes a parameter of a more concrete typeItalianPizzaFactory.PizzaType
.To cover the problem I have just mentioned and the problem stated in the post, I would suggest the following approach.
As you see, the ParseTag() method may be of arbitrary complexity, parsing a plain text or an encrypted value. Or the Tag field can be a simple int that is mapped internally to some pizza recipe table, with whole different recipes for even slightly changed pizza content.
您可以使用反射:
You can use reflection: