Builder设计模式和Factory设计模式有什么区别?
哪一个更有利,为什么?
如果我想测试并比较/对比这些模式,我如何将我的发现表示为图表?
答案 0 :(得分:406)
对于设计模式,通常没有“更有利”的解决方案适用于所有情况。这取决于您需要实施的内容。
来自维基百科:
- Builder专注于构建一个 复杂的对象一步一步。抽象 工厂强调一系列产品 对象(简单或复杂)。 Builder将产品作为最终产品返回 一步,但就摘要而言 工厂关注,产品得到 马上回来。
- Builder经常构建一个Composite。
- 通常,设计开始使用工厂方法(不太复杂,更多 可定制的,子类扩散) 并向抽象工厂发展, 原型或Builder(更灵活, 更复杂)作为设计师 发现更灵活的地方 需要的。
- 有时创作模式是互补的:Builder可以使用一个 其他模式的实施 哪些组件构建。抽象 Factory,Builder和Prototype都可以 在他们的使用中使用Singleton 的实施方式。
工厂设计模式的维基百科条目: http://en.wikipedia.org/wiki/Factory_method_pattern
维基百科的构建器设计模式条目: http://en.wikipedia.org/wiki/Builder_pattern
答案 1 :(得分:280)
工厂只是构造函数(可能是不同类中的一个)的包装函数。关键的区别在于工厂方法模式要求在单个方法调用中构建整个对象,所有参数都在一行中传递。最终的对象将被退回。
另一方面,构建器模式本质上是一个包装器对象,它围绕您可能希望传递给构造函数调用的所有可能参数。这允许您使用setter方法慢慢构建参数列表。构建器类的另一个方法是build()方法,它只是将构建器对象传递给所需的构造函数,并返回结果。
在Java这样的静态语言中,当您拥有多个(可能是可选的)参数时,这变得更加重要,因为它避免了为所有可能的参数组合设置伸缩构造器的要求。此外,构建器允许您使用setter方法来定义在调用构造函数后无法直接修改的只读或私有字段。
基本工厂示例
// 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");
基本构建器示例
// 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_pattern
http://en.wikipedia.org/wiki/Builder_pattern
答案 2 :(得分:259)
Factory模式几乎可以看作是Builder模式的简化版本。
在工厂模式中,工厂负责根据需要创建对象的各种子类型。
工厂方法的用户不需要知道该对象的确切子类型。工厂方法createCar
的示例可能会返回Ford
或Honda
类型的对象。
在构建器模式中,构建器方法也会创建不同的子类型,但对象的组成可能在同一个子类中有所不同。
要继续汽车示例,您可能有一个createCar
构建器方法,该方法创建一个带有4柱面引擎的Honda
类型对象,或带有6个柱面的Honda
类型对象。构建器模式允许更精细的粒度。
维基百科上提供Builder pattern和Factory method pattern的图表。
答案 3 :(得分:53)
构建器设计模式描述了一个知道如何通过几个步骤制作特定类型的另一个对象的对象。它在每个中间步骤保持目标项的所需状态。想想StringBuilder通过什么来生成最终的字符串。
工厂设计模式描述了一个对象,该对象知道如何在一个步骤中创建多个不同但相关的对象,其中基于给定参数选择特定类型。想想序列化系统,您可以在其中创建序列化程序,并在一次加载调用中构建所需的对象。
答案 4 :(得分:41)
逐步构建复杂对象:构建器模式
使用单个方法创建一个简单对象:工厂方法模式
使用多种工厂方法创建对象:抽象工厂模式
答案 5 :(得分:14)
两者都是Creational模式,用于创建Object。
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.
答案 6 :(得分:11)
Builder Pattern和Factory模式,看起来都非常类似于肉眼,因为它们都为你创造了对象。
这个现实生活中的例子将使两者之间的区别更加清晰。
假设您去了一家快餐店,并且您订购了食品。
披萨
辣椒,番茄,烧烤鸡,NO PINEAPPLE
因此,不同种类的食物是由工厂模式制作的,但特定食物的不同变体(风味)是由Builder模式制作的。
不同种类的食物
比萨饼,汉堡,意大利面
比萨饼的变种
只有奶酪,奶酪+番茄+辣椒,奶酪+番茄等。
您可以在此处查看两种模式的示例代码实现
Builder Pattern
Factory Pattern
答案 7 :(得分:10)
首先要遵循我的论证:
设计大型软件系统的主要挑战是它们必须灵活且不易变化。出于这个原因,有一些指标,如耦合和内聚。要实现易于更改或扩展其功能而无需从头开始重新设计整个系统的系统,您可以遵循设计原则(如SOLID等)。一段时间后,一些开发人员认识到,如果他们遵循这些原则,那么有一些类似的解决方这些标准解决方案被证明是设计模式。
因此,设计模式是为了支持您遵循一般设计原则,以实现具有高内聚力的松散耦合系统。
回答问题:
通过询问两种模式之间的区别,您必须问自己哪种模式可以使您的系统更灵活。每个模式都有自己的目的,即组织系统中各类之间的依赖关系。
抽象工厂模式: GoF:“提供一个接口,用于创建相关或依赖对象的族,而无需指定其具体类。”
这是什么意思: 通过提供这样的接口,对每个系列产品的构造函数的调用被封装在工厂类中。因为这是整个系统中唯一一个调用这些构造函数的地方,你可以通过实现一个新的工厂类来改变你的系统。如果您通过另一个交换工厂的代表,您可以交换一整套产品而无需接触大部分代码。
构建器模式: GoF:“将复杂对象的构造与其表示分开,以便相同的构造过程可以创建不同的表示。”
这是什么意思: 您将构造过程封装在另一个类中,称为director(GoF)。该导演包含创建产品新实例的算法(例如,从其他部分组成复杂产品)。为了创建整个产品的组成部分,导演使用了一个建筑师。通过在导向器中交换构建器,您可以使用相同的算法来创建产品,但更改单个部件的表示(以及产品的表示)。要在产品表示中扩展或修改系统,您只需要实现一个新的构建器类。
所以简而言之: 抽象工厂模式的目的是交换一组一起使用的产品。 Builder Pattern的目的是封装创建产品的抽象算法,以便将其重用于产品的不同表示。
在我看来,你不能说抽象工厂模式是Builder模式的大哥。是的,它们都是创作模式,但模式的主要意图完全不同。
答案 8 :(得分:6)
Builder和amp;之间的一个显着差异我能搞清楚的工厂是以下
假设我们有一辆车
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);
}
但如果在创建座位时发生了一些异常怎么办? 你根本不会获得对象// BUT
假设你有类似以下的实现
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();
}
在第二种情况下,即使一次操作失败,你仍然会得到汽车。
可能是因为汽车以后不能完美运行,但你会有这个对象。
因为Factory Method会在单次调用中为您提供Car,而Builder会逐个构建。
虽然,这取决于设计的需要。
答案 9 :(得分:4)
Builder 和抽象工厂具有不同的用途。根据正确的使用案例,您必须选择合适的设计模式。
Builder 显着特征:
工厂(简单工厂)显着特征:
通常,设计开始使用工厂方法(不太复杂,可定制,子类增加)并向抽象工厂, Prototype 演变,或 Builder (更灵活,更复杂)
查看相关帖子:
Keeping builder in separate class (fluent interface)
Design Patterns: Factory vs Factory method vs Abstract Factory
您可以参考以下文章了解更多详情:
答案 10 :(得分:4)
+-------------------------------------------------------------------+---------------------------------------------------+
| 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 |
+-------------------------------------------------------------------+---------------------------------------------------+
Telescoping Constructor Pattern
类比:
答案 11 :(得分:3)
抽象工厂&构建器模式都是Creational模式,但具有不同的意图。
抽象工厂模式强调相关对象族的对象创建,其中:
构建器模式专注于逐步构建复杂对象。 它将表示与构造复杂对象的过程分离,以便相同的构造过程可用于不同的表示。
答案 12 :(得分:3)
与工厂模式相比,构建器模式的主要优点是,如果您要创建带有许多可能的自定义项的标准对象,但是通常最终只能自定义一些。
例如,如果要编写HTTP客户端-您将设置一些默认参数,例如默认的写/读超时,协议,缓存,DNS,拦截器等。
客户端的大多数用户将仅使用这些默认参数,而其他一些用户则可能希望自定义其他一些参数。 在某些情况下,您只想更改超时并按原样使用其余部分,而在其他情况下,则可能需要自定义例如缓存。
以下是实例化客户端的可能方法(取自OkHttpClient):
//just give me the default stuff
HttpClient.Builder().build()
//I want to use custom cache
HttpClient.Builder().cache(MyCache()).build()
//I want custom connection timeout
HttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).build()
//I am more interested in read/write timeout
HttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS).build()
如果为此使用工厂模式,则最终将编写许多具有创建参数的所有可能组合的方法。 使用构建器,您只需指定您关心的对象,然后让构建器为您构建它,同时照顾所有其他参数。
答案 13 :(得分:2)
复杂的构造是指要构造的对象由不同的其他对象组成,这些对象由抽象表示。
考虑一下麦当劳的菜单。菜单包括饮料,主菜和饮品。根据各个抽象的后代组合在一起,创建的菜单有另一种表示。
在那里,我们得到了两个具有不同表示的菜单实例。反过来,施工过程保持不变。您可以创建一个包含饮料,主菜和饮料的菜单。
通过使用构建器模式,您可以将创建复杂对象的算法与用于创建它的不同组件分开。
就构建器模式而言,算法封装在导向器中,而构建器则用于创建整体部件。改变导演算法中使用的构建器会导致不同的表示,因为其他部分由菜单组成。创建菜单的方式保持不变。
答案 14 :(得分:2)
它们之间的主要区别是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();
}
答案 15 :(得分:1)
两者非常相似,但是如果您有大量参数用于创建对象,其中一些参数可选,但有一些默认值,请选择Builder模式。
答案 16 :(得分:1)
我相信,工厂和工厂的使用和区别当您处理相同的代码库并更改需求时,可以在特定时间段内更轻松地理解/澄清构建器模式。
根据我的经验,通常,您从一个工厂模式开始,包括几个静态创建方法。由于您的对象层次结构变得更加复杂(或者当您添加更多类型时),您最终可能会使用更多参数填充方法,更不用说您将需要重新编译Factory模块。所有这些都会增加创建者方法的复杂性,降低可读性并使创建模块更加脆弱。
这一点可能是过渡点。从Factory转换为Builder模式。通过这样做,您可以围绕构造参数创建一个包装器模块,然后您可以通过添加更多抽象(可能)和实现来表示新的(类似)对象,而无需触及实际的创建逻辑。所以你有更简单的逻辑和重新编译的源代码
坦率地说,指的是“有一个步骤或多个步骤创建的对象是不同的”,因为唯一的多样性因素不足以让我区分它们,因为我几乎可以在所有情况下使用两种方式面对现在没有经历任何好处。所以这就是我最终想到的。
答案 17 :(得分:1)
差异很明显 在构建器模式中,构建器将为您创建特定类型的对象。你必须告诉我们什么 建设者必须建立。 在工厂模式中,使用抽象类直接构建特定对象。
此处构建器类充当主类和特定类型类之间的中介。 更抽象。
答案 18 :(得分:0)
在我看来 当您想要从一堆其他对象创建对象时,将使用构建器模式,并且部件的创建需要独立于您要创建的对象。它有助于隐藏客户端部件的创建,以使构建器和客户端独立。它用于创建复杂对象(可能包含复杂属性的对象)
虽然工厂模式指定您要创建一个共同族的对象,并且您希望它立即被终止。它用于更简单的对象。
答案 19 :(得分:0)
两种模式都有相同的必要性:从一些客户端代码隐藏复杂对象的构造逻辑。但是什么使“复杂”(有时候,复杂化)成为一个对象呢?主要是,它是由于依赖性,或者更确切地说是由更多部分状态组成的对象的状态。您可以通过构造函数注入依赖项来设置初始对象状态,但是一个对象可能需要很多,有些将处于默认的初始状态(只是因为我们应该已经知道将默认依赖项设置为null并不是最干净的方式)和其他一些设置为由某种条件驱动的状态。此外,有些对象属性是某种“遗忘的依赖”,但它们也可以采用可选的状态。
有两种众所周知的方法来支配这种复杂性:
组合/聚合:构造一个对象,构造其依赖对象,然后连接在一起。在这里,构建者可以使过程变得透明和灵活,从而确定构成组件构造的规则。
多态性:构造规则直接声明为子类型定义,因此每个子类型都有一组规则,某些条件决定这些规则集中的哪一个适用于构造对象。工厂非常适合这种情况。
没有什么可以阻止混合这两种方法。一系列产品可以抽象使用构建器完成对象创建,构建器可以使用工厂来确定实例化哪个组件对象。
答案 20 :(得分:0)
构建模式强调创建对象的复杂性(通过"步骤"解决)
抽象模式强调"只是" on"抽象" (多个但相关的)对象。
答案 21 :(得分:0)
IMHO
Builder是某种更复杂的工厂。
但是在Builder中可以使用其他工厂实例化对象,这是构建最终和有效对象所必需的。
因此,通过复杂性来谈论“创造模式”的演变,你可以用这种方式思考它:
Dependency Injection Container -> Service Locator -> Builder -> Factory
答案 22 :(得分:0)
构建器和抽象工厂
Builder设计模式在某种程度上与抽象工厂模式非常相似。这就是为什么能够在使用一种或另一种情况之间产生差异的重要性。对于抽象工厂,客户端使用工厂的方法来创建自己的对象。在Builder的情况下,Builder类被指示如何创建对象然后它被要求它,但是类的组合方式取决于Builder类,这个细节使两个模式之间产生差异。
产品的通用界面
在实践中,由混凝土建造者创建的产品具有显着不同的结构,因此如果没有理由将不同的产品推导出共同的父类。这也将Builder模式与Abstract Factory模式区分开来,后者创建了从常见类型派生的对象。
答案 23 :(得分:0)
工厂:用于创建对象的实例,其中对象的依赖项完全由工厂保留。对于 抽象工厂模式 ,同一抽象工厂通常有许多具体实现。工厂的正确实现是通过依赖项注入来注入的。
Builder :用于构建 不可变 对象,当要实例化的对象的依赖项事先部分已知并且部分由建造者的客户。
答案 24 :(得分:0)
许多设计都是从 Factory方法(不太复杂,可以通过子类进行自定义)开始的,并逐渐发展为 Abstract Factory , Prototype 或< strong> Builder (更灵活,但更复杂)。
Builder 致力于逐步构造复杂的对象。
实施:
抽象工厂专门用于创建相关对象的族。 Abstract Factory 立即返回产品,而Builder使您可以在获取产品之前运行一些其他构造步骤。
您可以将 Abstract Factory 与 Bridge 一起使用。当Bridge定义的某些抽象只能用于特定的实现时,此配对很有用。在这种情况下,Abstract Factory可以封装这些关系并从客户端代码中隐藏复杂性。
答案 25 :(得分:-2)
工厂模式在运行时创建类的具体实现,即其主要目的是使用多态来允许子类决定实例化哪个类。这意味着在编译时我们不知道将要创建的确切类,而Builder模式主要涉及解决伸缩构造函数反模式的问题,这是由于类的大量可选字段而产生的。在构建器模式中,没有多态的概念,因为我们知道在编译时我们试图构造什么对象。
这两种模式的唯一共同主题是隐藏构造函数和工厂方法背后的对象创建,以及构建方法,用于改进对象构造。
答案 26 :(得分:-2)
工厂模式允许您一次创建一个对象,而构建器模式可以让您破坏对象的创建过程。通过这种方式,您可以在创建对象期间添加不同的功能。