我正在读欧莱利的“头第一设计模式”一书。在解释Factory方法模式之前,他们首先介绍了一个简单的Factory。
他们以比萨饼店为例。在第一步中,他们展示了这个问题:
Pizza orderPizza(string type) {
Pizza pizza;
if (type.equals("Pepperoni") { pizza = new PepperoniPizza(); }
else if (type.equals("Salmon") { pizza = new SalmonPizza(); }
// ... and so on
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Pack();
return pizza;
}显而易见的问题是,无论何时添加或移除比萨,都必须改变必胜客。
因此,他们首先引入了一个“简单工厂成语”。他们将创建部分移动到一个类"SimplePizzaFactory“中。现在,您不再需要在添加或移除比萨时修改Pizzeria了。
然后他们说,当你有一个以上的比萨饼店(在几个城镇)时,这种方法就没那么好了。
我不太明白他们的推理。他们给出了下面的示例代码,然后他们说每个比萨饼店不会使用上面实现的过程,而是使用不同的方法来“烤”、“切”和“包装”比萨饼。
BerlinPizzaFactory berlinFactory = new BerlinPizzaFactory();
Pizzeria berlinPizzeria = new Pizzeria(berlinFactory);
berlinPizza.Order("Pepperoni");他们建议使用Factory方法模式,而不是使用简单的Factory。
首先,我不明白为什么BerlinPizzeria不应该使用这个过程。它仍然是一种必胜客,当你点菜的时候,你使用的是同样的程序。
我最好的猜测是,他们暗示你能够实现,比方说,一个自助餐厅(我故意用完全不同的东西来说明我的观点),使用工厂(因为它独立于披萨店),并以你想要的方式准备披萨。
但是,即使在使用Factory方法模式时,也没有人强迫您使用默认过程。更简单的是“隐藏”你在做不同的事情。它们的代码示例是在Java中给出的,Java方法在默认情况下是虚拟的。因此,我将能够实现BerlinPizzeria和覆盖顺序(或者必须显式声明该方法为final)。然而,客户端不会注意到我的BerlinPizzeria所做的事情不同。
总之,我不认为简单的Factory和Factory方法模式有任何显著的区别。我看到的Factory方法模式的唯一优点是可以保存几个类(即“外包”工厂)。
那么,简单工厂的真正缺点是什么,为什么不是“外包”创建部分的好主意呢?
或者,Factory方法模式的真正优势是什么?为什么强制在子类中实现创建部分是一个好主意?
发布于 2014-08-31 09:57:24
让我们看看Simple Factory,Simple Factory的意图很简单:它生成具体类的实例。坚持您的示例:您有一个Pizzeria,其方法类似于order():
public enum Pizzas {
QUADDROSTAGGIONI, SALMONE, ROMANA
}
public class Pizzeria {
public static Pizza order(Pizzas type){
switch(type){
case ROMANA: return new Romana();
case SALMONE: return new Salmone();
case QUADDROSTAGGIONI: return new Quaddrostaggioni();
default: throw new NoRecipeException();
}
}
}这真的是一个工厂的简单例子。如果您决定要一个Salmone-Pizza,您只需订购一个这样的实例:
Pizza salmone=Pizzeria.order(Pizzas.SALMONE);优点:你把披萨的使用和它的创造分开了。你只想要比萨,独立于它的创作过程。你可以享受比萨而不用自己烤一份。
缺点:如果你有几种特定口味的比萨(例如ROMANABerlinStyle,ROMANAHamburgStyle),你有两种选择。
(一)在现有的青椒上加入新的一种。这扰乱了你的披萨店,你必须处理几种味道,它们并没有什么不同(例如,ROMANABerlinStyle添加大蒜,ROMANAHamburgStyle添加野生大蒜)。此外:知道这是没有好处的,你吃的是柏林式或汉堡式比萨饼。你只想从必胜客那里得到一些定义明确的比萨。
2)你进一步抽象化了一步:你将给定种类的QUADDROSTAGGIONI, SALMONE, ROMANA的个人口味分离成独立的工厂。这意味着,BerlinPizzeria知道它的配方,HamburgPizzeria也知道。
现在你可以有许多不同的比萨饼店,它们可以有自己的食谱:
传统的自上而下的必胜客
public class PizzeriaImpl implements Pizzeria {
public Pizza order(Pizzas type){
switch(type){
case ROMANA: return new Romana();
case SALMONE: return new Salmone();
case QUADDROSTAGGIONI: return new Quaddrostaggioni();
default: throw new NoRecipeException();
}
}
}和一种柏林风格的
public class BerlinPizzeriaImpl implements Pizzeria{
public Pizza order(Pizzas type){
switch(type){
case ROMANA: return new BerlinRomana();
case SALMONE: return new BerlinSalmone();
case QUADDROSTAGGIONI: return new Quaddrostaggioni();
default: throw new NoRecipeException();
}
}
}现在你可以开始你的特许经营了:
public class PizzaFranchiseImpl implements Pizzeria{
Pizzeria p;
public Pizza order(Pizzas type){
return p.order(type);
}
public PizzaFranchiseImpl(Pizzeria p){
this.p=p;
};
}如果你在柏林,你只需注射你的BerlinPizzeriaImpl。
优点:你可以自由决定你在每个城市(BerlinRomana,BerlinSalmone,传统的Quadrostaggioni)支持哪种口味。这对你的客户/消费者来说是完全透明的。
这遵循OpenClosed的原则:您的必胜客店关闭了,因为您有一套固定的比萨饼,您提供(QUADDROSTAGGIONI,SALMONE,ROMANA),但您是开放的新口味,例如贝林风格。
此外:每家比萨饼店本身都有一种比萨饼风格。BerlinPizzeriaImpl不在乎如何做传统的罗曼纳(单响应原则)。
最后但并非最不重要的是,你把不同的披萨风格与特许经营脱钩。特许经营只需要知道如何处理订单。
编辑:我用一条鲜美但死了的鱼代替了身体。
发布于 2014-09-02 12:13:03
首先,我读过那本书,我喜欢它。
简单工厂的经典实现只是一堆封装在一个类中的“静态创建”方法。
您可以争辩说,您将类的实现与其创建分离开来,但仅此而已。没有进一步的好处,甚至这一说法也是值得怀疑的。在我看来,您只是将一些创建静态方法分离到一个不同的文件中。
在大多数实际情况下,你会得到一个巨大的“文件”,它不仅会产生比萨,而且还会产生许多其他无关的物品,比如Burguers,Icecreams,.所以你违反了单一责任原则。这是因为在开始的时候,大多数事情都有几种创建方法,所以“自然”的事情是将它们分组,这样他们就不会在一个简单的工厂类中感到孤独。
因此,主要的缺点是杂乱。在大多数情况下,您的结果是大文件或许多小文件。
然而,最主要的是简单工厂不是一种设计模式,只是在某些情况下(例如单元测试)是一种有用的约定。在大多数情况下,您只需要两个create方法,这些方法可以包含在同一个类中(不需要外部类)。
如果您对一个类有很多创建方法,那么您就会遇到一个大问题:要么这个类做的太多了,要么认为传递参数是件坏事,或者是任何其他随机的原因。
与简单工厂不同的是,Factory方法使用继承来解决创建对象而不指定其确切类的问题。
等待代理章节。代理(简而言之)是一个“代表”另一个对象。在这种情况下,Factory方法可能很有用,因为您创建了一个实例,它可以是代理,也可以是真正的对象本身。
https://softwareengineering.stackexchange.com/questions/254923
复制相似问题