Builder Design模式和Factory Design模式有什么区别?

What is the difference between Builder Design pattern and Factory Design pattern?

建设者设计模式和工厂设计模式有什么区别?

哪一个更有利?为什么?

如果我想测试和比较/对比这些模式,如何将我的发现表示为一个图表?


对于设计模式,通常没有适用于所有情况的"更有利"的解决方案。这取决于您需要实现什么。

维基百科:

  • Builder focuses on constructing a
    complex object step by step. Abstract
    Factory emphasizes a family of product
    objects (either simple or complex).
    Builder returns the product as a final
    step, but as far as the Abstract
    Factory is concerned, the product gets
    returned immediately.
  • Builder often builds a Composite.
  • Often, designs start out using Factory Method (less complicated, more
    customizable, subclasses proliferate)
    and evolve toward Abstract Factory,
    Prototype, or Builder (more flexible,
    more complex) as the designer
    discovers where more flexibility is
    needed.
  • Sometimes creational patterns are complementary: Builder can use one
    of the other patterns to implement
    which components get built. Abstract
    Factory, Builder, and Prototype can
    use Singleton in their
    implementations.

工厂设计模式的维基百科条目:http://en.wikipedia.org/wiki/factory_method_模式

建设者设计模式的维基百科条目:http://en.wikipedia.org/wiki/builder_模式


工厂只是一个围绕构造函数的包装函数(可能是另一个类中的一个)。关键区别在于工厂方法模式要求在单个方法调用中构建整个对象,所有参数都在一行中传递。将返回最终对象。

另一方面,构建器模式本质上是一个包装器对象,它围绕着您可能希望传递到构造函数调用中的所有可能参数。这允许您使用setter方法缓慢构建参数列表。builder类上的另一个方法是build()方法,它只将builder对象传递到所需的构造函数中,并返回结果。

在像Java这样的静态语言中,当您拥有多于一个(可能是可选的)参数时,这变得更重要,因为它避免了对所有可能的参数组合具有伸缩构造函数的要求。此外,生成器允许您使用setter方法定义只读或私有字段,这些字段在调用构造函数后不能直接修改。

基本工厂示例

1
2
3
4
5
6
7
8
9
10
// Factory
static class FruitFactory {
    static Fruit create(name, color, firmness) {
        // Additional logic
        return new Fruit(name, color, firmness);
    }
}

// Usage
Fruit fruit = FruitFactory.create("apple","red","crunchy");

基本生成器示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Builder
class FruitBuilder {
    String name, color, firmness;
    FruitBuilder setName(name)         { this.name     = name;     return this; }
    FruitBuilder setColor(color)       { this.color    = color;    return this; }
    FruitBuilder setFirmness(firmness) { this.firmness = firmness; return this; }
    Fruit build() {
        return new Fruit(this); // Pass in the builder
    }
}

// Usage
Fruit fruit = new FruitBuilder()
        .setName("apple")
        .setColor("red")
        .setFirmness("crunchy")
        .build();

比较这两个维基百科页面的代码示例可能是值得的:

http://en.wikipedia.org/wiki/factory_method_模式http://en.wikipedia.org/wiki/builder_模式


工厂模式几乎可以看作是构建器模式的简化版本。

在工厂模式中,工厂负责根据需要创建对象的各种子类型。

工厂方法的用户不需要知道该对象的确切子类型。工厂方法createCar的示例可能返回FordHonda类型的对象。

在构建器模式中,构建器方法还创建了不同的子类型,但在同一个子类中,对象的组合可能有所不同。

为了继续汽车示例,您可能有一个createCar生成器方法,它创建一个具有4缸发动机的Honda类型对象,或者一个具有6缸的Honda类型对象。构建器模式允许这种更细的粒度。

构建器模式和工厂方法模式的图表都可以在维基百科上找到。


生成器设计模式描述了一个对象,该对象知道如何通过几个步骤来处理另一个特定类型的对象。它在每个中间步骤中保持目标项所需的状态。想想StringBuilder通过什么来生成最终的字符串。

工厂设计模式描述了一个对象,它知道如何在一个步骤中创建几个不同但相关的对象类型,在这个步骤中,根据给定的参数选择特定的类型。想想序列化系统,您在其中创建序列化程序,它在一次加载调用中构造所需的In对象All。


  • 逐步构造复杂对象:构建器模式

  • 一个简单的对象是通过使用一个方法创建的:工厂方法模式

  • 使用多工厂方法创建对象:抽象工厂模式


两者都是创造模式,创造对象。

1)工厂模式-假设您有一个超级类和n个子类。对象的创建取决于传递的参数/值。

2)构建器模式-创建复杂对象。

1
2
3
Ex: Make a Loan Object. Loan could be house loan, car loan ,
    education loan ..etc. Each loan will have different interest rate, amount ,  
    duration ...etc. Finally a complex object created through step by step process.

建设者模式和工厂模式,都看起来非常类似于肉眼,因为他们都为您创建对象。

但你得仔细看看

这个现实的例子将使两者之间的区别更加明显。

假设你去了一家快餐店,然后点了菜。

1)什么食物?

披萨

2)什么配料?

辣椒、番茄、烤鸡、无菠萝

因此,不同种类的食物是由工厂模式制造的,但特定食物的不同变体(风味)是由建设者模式制造的。

Different kinds of foods

披萨、汉堡、意大利面

Variants of Pizza

只有奶酪、奶酪+番茄+辣椒、奶酪+番茄等。

代码样本

您可以在这里看到两种模式的示例代码实现生成器模式工厂模式


首先,根据我的论证,我要做的一些一般性的事情是:

设计大型软件系统的主要挑战是它们必须灵活且简单,才能进行更改。因此,有一些度量标准,如耦合和内聚。为了实现在功能上易于更改或扩展的系统,而无需从头重新设计整个系统,您可以遵循设计原则(如Solid等)。过了一会儿,一些开发人员认识到,如果他们遵循这些原则,就有一些类似的解决方案可以很好地解决类似的问题。这些标准解决方案最终成为了设计模式。

因此,设计模式是为了支持您遵循一般的设计原则,以实现具有高内聚性的松散耦合系统。

回答问题:

通过问两种模式之间的区别,你必须问自己什么模式使你的系统以何种方式更灵活。每个模式都有自己的目的来组织系统中类之间的依赖关系。

抽象工厂模式:gof:"提供一个接口,用于创建相关或依赖对象的族,而不指定它们的具体类。"

这意味着什么:通过提供这样的接口,对每个系列产品的构造函数的调用被封装在工厂类中。因为这是整个系统中唯一调用这些构造函数的地方,所以您可以通过实现一个新的工厂类来更改系统。如果您通过另一个交换工厂的表示,您可以交换一组完整的产品,而无需接触大部分代码。

构建器模式:gof:"将复杂对象的构造与其表示分离,以便相同的构造过程可以创建不同的表示。"

这意味着什么:您将构造过程封装在另一个称为Director(GoF)的类中。此控制器包含创建产品新实例的算法(例如,用其他部分组成一个复杂的产品)。为了创建整个产品的完整部分,导演使用了一个构建器。通过交换Director中的生成器,您可以使用相同的算法来创建产品,但可以更改单个部件的表示(以及产品的表示)。要在产品的表示中扩展或修改系统,您需要做的就是实现一个新的生成器类。

简而言之:抽象工厂模式的目的是交换一组产品,这些产品被制成一起使用。构建器模式的目的是封装创建产品的抽象算法,以便将其用于产品的不同表示。

在我看来,你不能说抽象工厂模式是构建者模式的大哥。是的,它们都是创造性的模式,但是模式的主要意图是完全不同的。


建筑商和工厂之间的一个显著区别是:

假设我们有车

1
2
3
4
5
6
7
8
9
10
11
class Car
{
  bool HasGPS;
  bool IsCityCar;
  bool IsSportsCar;
  int   Cylenders;
  int Seats;

  public:
     void Car(bool hasGPs=false,bool IsCityCar=false,bool IsSportsCar=false, int Cylender=2, int Seats=4);
 };

在上述界面中,我们可以通过以下方式获得汽车:

1
2
3
4
 int main()
 {
    BadCar = new Car(false,false,true,4,4);
  }

但是,如果在创建座位时发生了一些异常情况呢????你根本拿不到这个东西//但是

假设您有如下的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Car
 {
    bool mHasGPS;
    bool mIsCityCar;
    bool mIsSportsCar;
    int mCylenders;
    int mSeats;

 public:
    void Car() : mHasGPs(false), mIsCityCar(false), mIsSportsCar(false), mCylender(2), mSeats(4) {}
    void SetGPS(bool hasGPs=false)  {mHasGPs = hasGPs;}
    void SetCity(bool CityCar)  {mIsCityCar = CityCar;}
    void SetSports(bool SportsCar)  {mIsSportsCar = SportsCar;}
    void SetCylender(int Cylender)  {mCylenders = Cylender;}    
    void SetSeats(int seat) {mSeats = seat;}    
};

 class CarBuilder
 {
    Car* mCar;
public:
        CarBuilder():mCar(NULL) {   mCar* = new Car();  }
        ~CarBuilder()   {   if(mCar)    {   delete mCar;    }
        Car* GetCar()   {   return mCar; mCar=new Car();    }
        CarBuilder* SetSeats(int n) {   mCar->SetSeats(n); return this; }
        CarBuilder* SetCylender(int n)  {   mCar->SetCylender(n); return this;  }
        CarBuilder* SetSports(bool val) {   mCar->SetSports(val); return this;  }
        CarBuilder* SetCity(bool val)   {   mCar->SetCity(val); return this;    }
        CarBuilder* SetGPS(bool val)    {   mCar->SetGPS(val); return this; }
}

现在你可以这样创造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 int main()
 {
   CarBuilder* bp =new CarBuilder;
    Car* NewCar  = bp->SetSeats(4)->SetSports(4)->SetCity(ture)->SetGPS(false)->SetSports(true)->GetCar();

     bp->SetSeats(2);

     bp->SetSports(4);

     bp->SetCity(ture);

     bp->SetSports(true)

     Car* Car_II=  bp->GetCar();

  }

在第二种情况下,即使一次操作失败,您仍然可以得到汽车。

也许那辆车以后不能很好地工作,但你会得到它的。

因为factory方法在单个调用中为您提供汽车,而builder则一个接一个地构建汽车。

尽管如此,这取决于设计的需要。


1
2
3
4
5
6
7
+-------------------------------------------------------------------+---------------------------------------------------+
|                              Builder                              |                      Factory                      |
+-------------------------------------------------------------------+---------------------------------------------------+
| Return only single instance to handle complex object construction | Retrun various instances on multiple constructors |
| No interface required                                             | Interface driven                                  |
| Inner classes is involved (to avoid telescopic constructors)      | Subclasses are involved                           |
+-------------------------------------------------------------------+---------------------------------------------------+

伸缩构造模式

类比:

  • 工厂:考虑一家餐馆。"今天的饭"的创建是一个工厂模式,因为你告诉厨房"得到今天的饭",而厨房(工厂)根据隐藏的标准决定要生成什么对象。
  • 建设者:如果您订购一个定制的比萨饼,建设者就会出现。在这种情况下,服务员告诉厨师(建筑商)"我需要一个比萨饼,加上奶酪、洋葱和培根!"因此,生成器公开生成的对象应该具有的属性,但隐藏了如何设置这些属性。

礼貌


建设者和抽象工厂有不同的目的。根据正确的用例,您必须选择合适的设计模式。

构建器显著特征:

  • 构建器模式使用简单对象和逐步方法构建复杂对象
  • 生成器类逐步生成最终对象。此生成器独立于其他对象
  • 在这种情况下替换为工厂方法/抽象工厂:从客户机程序传递到工厂类的参数太多,容易出错
  • 有些参数可能是可选的,与工厂强制发送所有参数不同
  • 工厂(简单工厂)显著特点:

  • 创建型模式
  • 基于继承
  • 工厂返回工厂方法(接口),该方法反过来返回具体对象
  • 您可以为接口替换新的具体对象,客户机(调用者)不应该知道所有具体实现。
  • 客户端总是只访问接口,您可以在工厂方法中隐藏对象创建详细信息。
  • 通常,设计从使用工厂方法开始(不那么复杂,更可定制,子类激增),然后发展到抽象工厂、原型或构建器(更灵活,更复杂)

    查看相关帖子:

    将生成器保持在单独的类中(Fluent接口)

    设计模式:工厂vs工厂方法vs抽象工厂

    有关详细信息,请参阅以下文章:

    源代码化

    记事本


    抽象工厂和生成器模式都是创造性的模式,但目的不同。

    抽象工厂模式强调为相关对象族创建对象,其中:

    • 每个族都是从公共的基类/接口派生的一组类。
    • 每个对象都会作为一个调用的结果立即返回。

    构建器模式专注于逐步构造复杂的对象。它将表示与构造复杂对象的过程分离,以便相同的构造过程可以用于不同的表示。

    • Builder对象封装复杂对象的配置。
    • Director对象知道使用生成器的协议,其中协议定义了构建复杂对象所需的所有逻辑步骤。


    复杂的构造是指要构造的对象由不同的其他对象组成,这些对象由抽象表示。

    以麦当劳的菜单为例,菜单包括饮料、主菜单和侧菜单。根据各个抽象的后代组合在一起,创建的菜单具有另一种表示形式。

  • 例如:可乐、巨无霸汉堡、炸薯条
  • 例如:雪碧、金块、卷毛薯条
  • 在这里,我们得到了两个具有不同表示形式的菜单实例。施工过程依次保持不变。您可以创建一个包含饮料、主菜单和侧菜单的菜单。

    通过使用构建器模式,可以将创建复杂对象的算法与用于创建复杂对象的不同组件分离开来。

    就构建器模式而言,该算法封装在Director中,而构建器用于创建完整的部分。在Director算法中更改所用的生成器会导致不同的表示,因为其他部分组成了一个菜单。创建菜单的方式保持不变。


    差别很明显在构建器模式中,构建器将为您创建特定类型的对象。你得说什么建筑商必须建造。在工厂模式中,使用抽象类直接构建特定对象。

    这里,builder类充当主类和特定类型类之间的中介。更抽象。


    我相信,当您处理相同的代码库和不断变化的需求时,在特定的时间段内,可以更容易地理解/澄清工厂和生成器模式的用法以及它们之间的差异。

    根据我的经验,通常,您从工厂模式开始,包括两个静态的creator方法。随着对象层次结构变得越来越复杂(或者随着添加更多类型),您可能最终会使用更多的参数填充方法,更不用说必须重新编译工厂模块了。所有这些东西,增加了创建者方法的复杂性,降低了可读性,使创建模块更加脆弱。

    这一点可能是过渡点。从工厂到建筑商模式的转换。通过这样做,您可以围绕构造参数创建一个包装模块,然后通过添加更多的抽象(可能)和实现来表示新的(类似的)对象,而无需接触实际的创建逻辑。所以你已经有了不那么复杂的逻辑和重新编译的源代码

    坦率地说,指的是"一步或多步创造一个物体是不同的",因为唯一的多样性因素不足以让我区分它们,因为我可以用这两种方法来处理几乎所有我现在面对的情况,而不必经历任何好处。所以这就是我最后想到的。


    两者都非常相似,但是如果您有大量用于对象创建的参数,其中一些参数是可选的,带有一些默认值,请使用构建器模式。


    工厂:用于创建对象的实例,其中对象的依赖项完全由工厂持有。对于抽象工厂模式,通常有许多同一抽象工厂的具体实现。工厂的正确实现是通过依赖注入来注入的。

    builder:用于构建不可变对象,当要实例化的对象的依赖关系部分提前已知,部分由builder的客户端提供时。


    在我看来当您想要从一堆其他对象创建一个对象,并且创建零件需要独立于您想要创建的对象时,可以使用构建器模式。它有助于从客户机隐藏零件的创建,以使构建器和客户机独立。用于创建复杂对象(可能包含复杂属性的对象)

    而工厂模式指定要创建公共族的对象,并希望立即对其进行陶瓷处理。它用于更简单的对象。


    构建模式强调创建对象的复杂性(通过"步骤"解决)

    抽象模式强调(多个但相关的)对象的"抽象"。


    Builder and Abstract Factory

    The Builder design pattern is very similar, at some extent, to the Abstract Factory pattern. That's why it is important to be able to make the difference between the situations when one or the other is used. In the case of the Abstract Factory, the client uses the factory's methods to create its own objects. In the Builder's case, the Builder class is instructed on how to create the object and then it is asked for it, but the way that the class is put together is up to the Builder class, this detail making the difference between the two patterns.

    Common interface for products

    In practice the products created by the concrete builders have a structure significantly different, so if there is not a reason to derive different products a common parent class. This also distinguishes the Builder pattern from the Abstract Factory pattern which creates objects derived from a common type.

    发件人:http://www.oodesign.com/builder-pattern.html


    这两种模式都有相同的必要性:对某些客户机代码隐藏复杂对象的构造逻辑。但是什么使"复杂"(或者有时使)一个物体变得复杂呢?主要是由于依赖关系,或者更确切地说,是由部分状态组成的对象的状态。您可以通过构造函数注入依赖项来设置初始对象状态,但是一个对象可能需要很多依赖项,其中一些将处于默认初始状态(只是因为我们应该知道将默认依赖项设置为空不是最干净的方法),而另一些则设置为由某些条件驱动的状态。此外,还有一些对象属性是某种"遗忘的依赖关系",但它们也可以假定为可选状态。

    有两种众所周知的方法来控制这种复杂性:

    • 组合/聚合:构造一个对象,构造它的依赖对象,然后连接在一起。在这里,构建者可以使确定引导组件构造的规则的过程透明和灵活。

    • 多态性:构造规则直接声明到子类型定义中,因此每个子类型都有一组规则,并且某些条件决定了这些规则中的哪一个应用于构造对象。工厂完全适合这种情况。

    没有什么能阻止混合这两种方法。一个产品系列可以抽象一个构建器完成的对象创建,一个构建器可以使用工厂来确定哪个组件对象被实例化。


    IMHO

    建筑商是一个比较复杂的工厂。

    但是在构建器中,您可以使用另一个工厂来实例化对象,这是构建最终有效对象所必需的。

    因此,谈到"创造模式"的复杂性演变,你可以这样想:

    1
    Dependency Injection Container -> Service Locator -> Builder -> Factory

    工厂模式在运行时创建类的具体实现,即其主要目的是使用多态性来允许子类决定要实例化哪个类。这意味着在编译时我们不知道将要创建的确切类,而构建器模式主要是解决伸缩构造函数反模式的问题,这是由于类的大量可选字段而产生的。在构建器模式中,没有多态性的概念,因为我们知道在编译时要构造什么对象。

    这两种模式唯一的共同主题是隐藏构造函数和工厂方法后面的对象创建,以及改进对象构造的构建方法。


    工厂模式允许您一次创建一个对象,而构建器模式允许您中断对象的创建过程。通过这种方式,您可以在创建对象的过程中添加不同的功能。