首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >“简单工厂”的缺点是什么?

“简单工厂”的缺点是什么?
EN

Software Engineering用户
提问于 2014-08-31 08:01:10
回答 2查看 7.2K关注 0票数 4

我正在读欧莱利的“头第一设计模式”一书。在解释Factory方法模式之前,他们首先介绍了一个简单的Factory。

他们以比萨饼店为例。在第一步中,他们展示了这个问题:

代码语言:javascript
复制
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了。

然后他们说,当你有一个以上的比萨饼店(在几个城镇)时,这种方法就没那么好了。

我不太明白他们的推理。他们给出了下面的示例代码,然后他们说每个比萨饼店不会使用上面实现的过程,而是使用不同的方法来“烤”、“切”和“包装”比萨饼。

代码语言:javascript
复制
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方法模式的真正优势是什么?为什么强制在子类中实现创建部分是一个好主意?

EN

回答 2

Software Engineering用户

发布于 2014-08-31 09:57:24

让我们看看Simple FactorySimple Factory的意图很简单:它生成具体类的实例。坚持您的示例:您有一个Pizzeria,其方法类似于order()

代码语言:javascript
复制
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,您只需订购一个这样的实例:

代码语言:javascript
复制
  Pizza salmone=Pizzeria.order(Pizzas.SALMONE);

优点:你把披萨的使用和它的创造分开了。你只想要比萨,独立于它的创作过程。你可以享受比萨而不用自己烤一份。

缺点:如果你有几种特定口味的比萨(例如ROMANABerlinStyle,ROMANAHamburgStyle),你有两种选择。

(一)在现有的青椒上加入新的一种。这扰乱了你的披萨店,你必须处理几种味道,它们并没有什么不同(例如,ROMANABerlinStyle添加大蒜,ROMANAHamburgStyle添加野生大蒜)。此外:知道这是没有好处的,你吃的是柏林式或汉堡式比萨饼。你只想从必胜客那里得到一些定义明确的比萨。

2)你进一步抽象化了一步:你将给定种类的QUADDROSTAGGIONI, SALMONE, ROMANA的个人口味分离成独立的工厂。这意味着,BerlinPizzeria知道它的配方,HamburgPizzeria也知道。

现在你可以有许多不同的比萨饼店,它们可以有自己的食谱:

传统的自上而下的必胜客

代码语言:javascript
复制
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();
        }
    }

}

和一种柏林风格的

代码语言:javascript
复制
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();
        }
    }

}

现在你可以开始你的特许经营了:

代码语言:javascript
复制
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不在乎如何做传统的罗曼纳(单响应原则)。

最后但并非最不重要的是,你把不同的披萨风格与特许经营脱钩。特许经营只需要知道如何处理订单。

编辑:我用一条鲜美但死了的鱼代替了身体。

票数 4
EN

Software Engineering用户

发布于 2014-09-02 12:13:03

首先,我读过那本书,我喜欢它。

简单工厂的经典实现只是一堆封装在一个类中的“静态创建”方法。

您可以争辩说,您将类的实现与其创建分离开来,但仅此而已。没有进一步的好处,甚至这一说法也是值得怀疑的。在我看来,您只是将一些创建静态方法分离到一个不同的文件中。

在大多数实际情况下,你会得到一个巨大的“文件”,它不仅会产生比萨,而且还会产生许多其他无关的物品,比如Burguers,Icecreams,.所以你违反了单一责任原则。这是因为在开始的时候,大多数事情都有几种创建方法,所以“自然”的事情是将它们分组,这样他们就不会在一个简单的工厂类中感到孤独。

因此,主要的缺点是杂乱。在大多数情况下,您的结果是大文件或许多小文件。

然而,最主要的是简单工厂不是一种设计模式,只是在某些情况下(例如单元测试)是一种有用的约定。在大多数情况下,您只需要两个create方法,这些方法可以包含在同一个类中(不需要外部类)。

如果您对一个类有很多创建方法,那么您就会遇到一个大问题:要么这个类做的太多了,要么认为传递参数是件坏事,或者是任何其他随机的原因。

与简单工厂不同的是,Factory方法使用继承来解决创建对象而不指定其确切类的问题。

等待代理章节。代理(简而言之)是一个“代表”另一个对象。在这种情况下,Factory方法可能很有用,因为您创建了一个实例,它可以是代理,也可以是真正的对象本身。

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/254923

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档