【问题标题】:Difference between Abstract factory and builder?抽象工厂和生成器之间的区别?
【发布时间】:2014-09-02 00:37:11
【问题描述】:

抱歉再次询问。我在网上搜索过,但无法理解,因此我必须放在这里。这里是我自己研究的。我从 head first 设计模式学习。

抽象工厂模式:

根据我研究的差异,建造者有些感觉它是工厂,但是 大多数情况下,它只创建一种类型。
那么我可以说上图中的 NYStore 是构建器,因为它将披萨对象返回给客户端? 我对么?请根据上面的例子给出你的答案,这可能有助于我学习它。

【问题讨论】:

标签: design-patterns builder abstract-factory


【解决方案1】:

Builder 包含构建整体特定部分所需的知识,调用工厂来制造所需的部分。 Abstract Factory 确保创建一组一致的这些部分。例如,我可能有一个 FordBuilder 用于组装福特汽车,GMBuilder 用于组装通用汽车。现在使用Builder模式,客户端可以调用director的制造方法。

class Director
...
Vehicle manufacture(VehicleBuilder builder)
{
    builder.buildFrame();
    builder.buildDoors(2);
    builder.buildWheels(4);
    return builder.GetVehicle()
}

请注意,虽然导演给出了指示,但知道这些部分如何组合在一起以形成一个连贯的整体的建设者。所以FordBuilder 知道如何通过调用方法来组装车架,方法是为车架调用makeFrame(),为门调用makeDoor(),为某些工厂类调用makeWheel() 为轮子调用ComponentFactoryGMBuilder 对 GM 也是如此。现在假设我们想使用相同的制造商来制造卡车或轿车,因为我们看到两者的步骤是相同的​​。但是,车架、车门和车轮的组合必须兼容,不能将轿车车架与卡车车轮混合使用!这就是 Abstract Factory 模式的用武之地。抽象类或接口AbstractComponentFactory 支持刚才提到的 3 种方法。现在FordSedanFactory 的子类AbstractComponentFactory 实现了makeFrame()makeDoor()makeWheel(),并确保它们都返回兼容的轿车框架、门和​​轮子。 FordTruckFactory 确保卡车也是如此。现在,特定的制造商FordBuilderGMBuilder 可以按照客户的要求执行制造轿车或卡车的流程或配方,根据需要拨打makeFrame()makeDoor()makeWheel(),在知识上安全下线的是一辆合适的轿车或卡车,而不是一些不起作用的嵌合体。

【讨论】:

    【解决方案2】:

    在披萨示例中,如果 NYstore 充当客户端,那么它会从工厂获取 productA、produtB... 等并可以直接访问,但如果我们将 NYStore 视为披萨厨师(如 tcarvin 建议的那样)并且客户端访问它以获得完整的披萨,它充当构建器(pizzache 作为directe,成分类作为构建器) 下图可以准确地说明确切的区别是什么 注意:我放这张图片是为了让访问这篇文章的人都能轻松理解。

    现在我也饿了。

    感谢 liviu 提供这张图片。

    【讨论】:

      【解决方案3】:

      有趣。我建议对图表进行一些更改,使其符合 GoF 定义的经典 Builder 模式。

      最大的区别在于,在构建器模式中,“主管”不知道构建器的细节。因此,与其拥有一个名为NyPizzaStore 的类和一个名为createPizza() 的方法(显然)非常适合创建纽约风格的比萨饼,不如你可能有一个类调用PizzaChef,它接收一个类的实例:定制如何制作比萨的细节。 (对于这个例子/类比,让我们将 renamePizzaIngerdientFactory 重命名为 Recipe 以便我们可以稍微不同地对待它)。这给了你PizzaChef.createPizza(Recipe r)。 PizzaChef 类不需要担心蛤蜊是新鲜的还是冷冻的,他只需依次调用每个构建器并创建所需的披萨。这是差异的关键……只有一个 PizzaChef,他不知道食谱的细节(子类)。

      这样做的一个很好的副作用是,您可以轻松混合和匹配构成 Recipe 类的构建器,这样您就可以使用与 NYStyle 相同的所有成分构建器来创建 NewHavenStyle 披萨,但换成BrickFiredThinCrust 代替。更可定制。 Recipe 成为构建器实例的持有者。

      当然,现在我饿了:)


      请注意不要混淆模式的名称(这是一种几乎总是涉及多个对象/参与者/角色的可重用技术)和模式中特定角色的名称。此外,模式通常建立在彼此之上并且有很多重叠。

      在 Builder pattern 中,有一个 Director 对象,它有一个 createSomething() 方法(不调用它)。该方法将以一种非常公式化的方式调用一个或多个部分构建器。客户端引用了Director,并传入了构建器。客户直接或间接地影响构建的内容。 Director 不需要是任何东西的子类,它可以是一个简单的、密封的类。 PizzaChef 不是客户而是导演。它不会从任何东西继承,也不会被继承。在这种情况下,客户端可能类似于 Customer 类。

      现在,正如 Abstract Factory 模式是基于一组 Factory Methods (来自该名称的模式),您可以让 Builder 模式使用 Abstract Factory 。您可以将构建器作为 AbstractFactory 传递给 Director。在这种情况下,Recipe 将是您的 AbstractFactory,NyStyleRecipe 将继承 Recipe 并提供 PizzaChef 类将用于创建比萨饼的构建器方法。在这个特定的实现中,Builder 模式的Directpr 确实是您原始图表中描述的客户端。

      但正如我之前试图暗示的那样,这并不是实现Builder 模式的唯一必要条件,我认为它增加了 Builder 旨在克服的限制。我会改用可组合的Recipe 类,因为这样您就可以更轻松地混合搭配成分。 真的薄皮和纽约风格的披萨之间没有联系。纽黑文风格也使用细风格。

      Recipe newyorkStyle = new Recipe(
         new ThinCrustBuilder(), 
         new RedSauceBuilder(), 
         new FreshClamsBuilder(), 
         new ElectricOvenBuilder());
      
      Recipe newhavenStyle = new Recipe(
         new ThinCrustBuilder(), 
         new WhiteSauceBuilder(), 
         new FreshClamsBuilder(), 
         new BrickOvenBuilder());
      
      PizzaChef chef = new PizzaChef ();
      
      nyPizza = checf.createPizza(newyorkStyle);
      
      nhPizza = checf.createPizza(newhavenStyle);
      

      请注意,我使用可组合构建器来重复使用薄壳和新鲜蛤蜊。使用Abstract Factory 就不会那么容易了

      我希望能进一步澄清差异!

      【讨论】:

      • 所以我的理解是,如果在上面的示例 NYStore 作为客户端,它是一个抽象工厂。但是,如果某些主管尝试调用 NYStore createpizza 方法来获取单个比萨对象(由其他成分对象组成),那么 NYStore 是一个构建器。我对么?我特别喜欢你的回答,现在我很饿了 :)
      • 已编辑以增加清晰度,如果您有任何其他问题,请告诉我
      【解决方案4】:

      构建器和抽象工厂模式的相似之处在于它们都在抽象级别上看待构造。然而,建造者模式关注的是如何 单个对象由不同的工厂组成,而抽象工厂模式 关心生产什么产品。建造者模式抽象了 通过包含导演的概念来构建算法。导演是 负责逐项列出步骤并呼吁建设者完成这些步骤。董事们 不必符合接口。

      其他示例(除了您的示例)可能是创建产品而不是客户 显式声明 ProductA 和 ProductB 类型的字段,例如 Product 对象 builder返回的其实是一个part列表,可以有不同的长度和内容 取决于负责创建它的导演。

      【讨论】:

      • 所以我可以说 NYStore 是构建器,因为它返回的比萨对象是面团、酱汁、蔬菜等对象的组合?
      • 是的。但请记住构建一个对象(在您的示例中添加面团、酱汁等),而不是返回它。这是因为有这种云模式 CQRS(如果您熟悉的话),它表示方法要么更改对象要么返回(读取)它们,但不能同时返回(读取)它们。
      • 顺便说一句,如果我的回答对您有帮助,请不要犹豫,给它评分或至少批准它。我会上传一张图片以便更容易理解,但我没有足够的声誉:D
      • 完成。如果可能的话,你能把带有解释详细信息的图片发送到surendersinghpawar@gmail.com,我可以上传答案。
      猜你喜欢
      • 1970-01-01
      • 2017-07-31
      • 2021-03-21
      • 2014-08-12
      • 2017-07-10
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 2016-07-11
      相关资源
      最近更新 更多