Builder Design模式和工厂设计模式有什么区别?

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

哪一个更有利,为什么?

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

350682 次浏览

构建器设计模式描述了一个对象,它知道如何通过几个步骤制作另一个特定类型的对象。它在每个中间步骤保存目标项所需的状态。想想StringBuilder生成最终字符串的过程。

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

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

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

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

Builder模式中,不同的子类型也由构建器方法创建,但对象的组成在同一个子类中可能不同。

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

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

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

来自wikipedia:

  • Builder专注于构建一个一步一步地复杂对象。抽象工厂强调产品的家庭对象(简单或复杂)。Builder将产品作为最终结果返回步,但就抽象而言工厂关注,产品得到立即返回。
  • 生成器经常构建一个复合。
  • 通常,设计开始使用工厂方法(不太复杂,更多可定制,子类激增)并向抽象工厂发展,原型或构建器(更灵活,更复杂)作为设计师发现哪里更灵活需要
  • 有时创建模式是互补的:Builder可以使用一个要实现的其他模式构建哪些组件。抽象工厂、生成器和原型可以在其实现。

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

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

两者都是创建模式,用于创建对象。

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

2)生成器模式-创建复杂的对象。

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.

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

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

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

基本工厂示例

// Factorystatic class FruitFactory {static Fruit create(name, color, firmness) {// Additional logicreturn new Fruit(name, color, firmness);}}
// UsageFruit fruit = FruitFactory.create("apple", "red", "crunchy");

基本生成器示例

// Builderclass 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}}
// UsageFruit fruit = new FruitBuilder().setName("apple").setColor("red").setFirmness("crunchy").build();

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

http://en.wikipedia.org/wiki/Factory_method_pattern
http://en.wikipedia.org/wiki/Builder_pattern

建造者和抽象工厂

Builder设计模式在某种程度上与抽象工厂模式非常相似。这就是为什么能够区分使用其中一种的情况非常重要。在抽象工厂的情况下,客户端使用工厂的方法来创建自己的对象。在Builder的情况下,Builder类被指示如何创建对象,然后被要求,但是类的组合方式取决于Builder类,这个细节决定了两种模式之间的区别。

产品通用接口

在实践中,具体构建器创建的产品具有显着不同的结构,因此如果没有理由派生不同的产品,则使用公共父类。这也将Builder模式与抽象工厂模式区分开来,后者创建派生自公共类型的对象。

来自:http://www.oodesign.com/builder-pattern.html

构建模式强调创建对象的复杂性(由“步骤”解决)

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

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

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

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

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

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

在我看来生成器模式用于当你想从一堆其他对象中创建一个对象,并且部分的创建需要独立于你想创建的对象时。它有助于向客户端隐藏部分的创建,使生成器和客户端独立。它用于复杂对象的创建(可能由复杂属性组成的对象)

而工厂模式指定您要创建一个公共系列的对象并且您希望它立即被选中。它用于更简单的对象。

Builder和工厂之间的一个显着区别,我可以做出以下几点

假设我们有一辆车

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);};

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

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

但是,如果在创建座位时发生一些异常怎么办???你将不会得到对象在所有//但是

假设您有如下实现

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; }}

现在你可以像这样创造

 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();
}

在第二种情况下,即使一个操作失败,你仍然会得到汽车。

也许那辆车以后不能完美地工作,但是,你会有对象。

因为工厂方法在单个调用中为您提供Car,而Builder一个接一个地构建。

虽然,这取决于屈尊的需要去哪一个。

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

抽象工厂模式和Builder模式都是创作模式,但具有不同的意图。

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

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

生成器模式专注于一步一步地构建一个复杂的对象。它将表示与构造复杂对象的过程解耦,以便相同的构造过程可以用于不同的表示。

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

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

Builder显著特点:

  1. 生成器模式使用简单对象并使用逐步方法构建复杂对象
  2. Builder类逐步构建最终对象。这个生成器独立于其他对象
  3. 在这种情况下替换为Factory方法/抽象工厂:从客户端程序传递给Factory类的参数太多,可能容易出错
  4. 一些参数可能是可选的,不像在工厂中强制发送所有参数

工厂(简单工厂)显著特点:

  1. 创作模式
  2. 基于继承
  3. 工厂返回一个工厂方法(接口),它又返回具体对象
  4. 你可以用新的具体对象代替接口,客户端(调用者)不应该知道所有的具体实现
  5. 客户端始终仅访问接口,您可以在Factory方法中隐藏对象创建详细信息。

通常,设计开始使用工厂方法(不太复杂,更可定制,子类激增)并向抽象工厂原型Builder(更灵活,更复杂)发展

看看相关的帖子:

保持构建器在单独的类中(流利的接口)

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

你可以参考下面的文章了解更多细节:

源代码制作

日志

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

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

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

我相信,当您在相同的代码库和不断变化的需求上工作时,可以在特定的时间段内更容易理解/澄清Factory&Builder模式的用法和区别。

根据我的经验,通常,你从工厂模式开始,包括几个静态创建者方法,以主要隐藏相对复杂的初始化逻辑。随着你的对象层次结构变得更加复杂(或者当你添加更多类型、参数时),你可能最终会让你的方法填充更多参数,更不用说你必须重新编译你的工厂模块。所有这些都会增加创建者方法的复杂性,降低易读性,并使创建模块更加脆弱。

这个点可能是转换/扩展点。通过这样做,你围绕施工参数创建了一个包装器模块,然后你将能够通过添加更多的抽象(也许)和实现来表示新的(类似的)对象,而无需触及实际的创建逻辑。所以你有了“更少”的复杂逻辑。

坦率地说,把“一个对象是分一步创建还是分多步创建就是区别”这种说法作为唯一的多样性因素,并不足以让我区分它们,因为到目前为止,几乎所有的情况我都可以同时使用这两种方法,而没有任何好处。所以这是我最终想到的。

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

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

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

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

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

首先,一些一般的事情遵循我的论点:

设计大的软件系统的主要挑战在于,它们必须灵活且不复杂。因此,有一些指标,比如耦合和内聚。为了实现系统可以容易地在功能上改变或扩展,而不需要从头开始重新设计,你可以遵循设计原则(比如SOLID等)。一段时间后,一些开发人员意识到,如果他们遵循这些原则,那么一些类似的解决方案可以很好地解决类似的问题。那些标准的解决方案后来被证明是设计模式。

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

回答这个问题:

通过询问两种模式之间的区别,您必须问自己哪种模式使您的系统更灵活。每种模式都有自己的目的来组织系统中类之间的依赖关系。

<强>抽象工厂模式:GoF:“提供一个接口来创建相关或依赖对象的系列,而无需指定它们的具体类。”

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

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

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

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

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

构建器模式和工厂模式看起来都与肉眼非常相似,因为它们都为您创建对象。

但你得仔细看看

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

假设你去了一家快餐店,你点了食物

(1)什么食物?

披萨

2)什么配料?

辣椒,番茄,烤鸡,NO菠萝

因此,不同种类的食物是由工厂模式制成的,但特定食物的不同变体(口味)是由Builder模式制成的。

不同种类的食物

披萨,汉堡,意面

披萨的变种

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

代码示例

您可以在此处查看两种模式的示例代码实现
生成器模式
工厂模式

IMHO

Builder是某种更复杂的工厂。

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

所以,谈论“创造模式”的复杂性进化,你可以这样想:

Dependency Injection Container -> Service Locator -> Builder -> Factory
Builder工厂
只返回单个实例来处理复杂的对象构造返回多个构造函数上的各种实例
无需接口接口驱动
涉及内部类(以避免伸缩构造函数)涉及子类

伸缩构造器模式

类比:

  • 工厂:考虑一个餐厅,“今天的饭菜”的创建是一个工厂模式,因为你告诉厨房“给我今天的饭菜”,厨房(工厂)根据隐藏的标准决定要生成什么对象。
  • 建设者:如果您订购自定义披萨,则会出现构建器。在这种情况下,服务员告诉厨师(构建器)“我需要一个披萨;添加奶酪,洋葱和培根!”因此,构建器公开了生成对象应该具有的属性,但隐藏了如何设置它们。

礼貌

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

考虑麦当劳的菜单。菜单包含饮料、主菜和配菜。根据单个抽象的后代组合在一起,创建的菜单有另一种表示。

  1. 例如:可乐、巨无霸、薯条
  2. 示例:雪碧、掘金、卷薯条

在那里,我们得到了两个具有不同表示的菜单实例。构建过程依次保持不变。您创建一个包含饮料、主菜单和侧面菜单。

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

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

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

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

它们之间的主要区别在于,Builder模式主要描述了逐步创建复杂对象。在抽象工厂模式中,重点是对象产品族。Builder在最后一步中返回产品。而在抽象工厂模式中,产品是立即可用

示例:假设我们正在创建迷宫

1.抽象工厂:

Maze* MazeGame::CreateMaze (MazeFactory& factory) {Maze* maze = factory.MakeMaze(); /// product is available at start!!/* Call some methods on maze */return maze;}

2.建造者:

Maze* MazeGame::CreateMaze (MazeBuilder& builder) {builder.buildMaze(); /// We don't have access to maze/* Call some methods on builder */return builder.GetMaze();}

构建器模式相对于工厂模式的主要优势是,如果您想创建一些具有许多可能自定义的标准对象,但您通常最终只自定义了几个。

例如,如果您想编写HTTP客户端-您将设置一些默认参数,例如默认写/读超时、协议、缓存、DNS、拦截器等。

客户端的大多数用户只会使用这些默认参数,而其他一些用户可能想要自定义一些其他参数。在某些情况下,您只需要更改超时并按原样使用其余部分,而在其他情况下,您可能需要自定义例如缓存。

以下是实例化客户端的可能方法(取自OkHttpClient):

//just give me the default stuffHttpClient.Builder().build()
//I want to use custom cacheHttpClient.Builder().cache(MyCache()).build()
//I want custom connection timeoutHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).build()
//I am more interested in read/write timeoutHttpClient.Builder().readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).build()

如果您为此使用工厂模式,您最终会编写很多方法,其中包含所有可能的创建参数组合。使用构建器,您只需指定您关心的那些参数,并让构建器为您构建所有其他参数。

许多设计从使用工厂方法(不太复杂,通过子类更可定制)开始,并向抽象工厂原型Builder(更灵活,但更复杂)发展。

Builder专注于逐步构建复杂对象。

实施它:

  1. 明确定义构建所有可用产品表示的常见构建步骤。否则,您将无法继续实现该模式。
  2. 在基本构建器接口中声明这些步骤。
  3. 为每个产品表示创建一个具体的构建器类并实现它们的构建步骤。

抽象工厂专门创建相关对象的系列。抽象工厂立即返回产品,而Builder允许您在获取产品之前运行一些额外的构造步骤。

您可以将抽象工厂Bridge一起使用。当Bridge定义的某些抽象只能与特定实现一起使用时,这种配对很有用。在这种情况下,抽象工厂可以封装这些关系并向客户端代码隐藏复杂性。

深入了解设计模式