Builderdevise模式和Factory Design模式有什么区别?
Builderdevise模式和Factorydevise模式有什么区别?
哪一个更有利,为什么?
如果我想对这些模式进行testing和比较/对比,如何将我的发现表示为图表?
对于devise模式,通常没有适用于所有情况的“更有利”的解决scheme。 这取决于你需要实现什么。
维基百科:
- Builder着重于逐步构build一个复杂的对象。 抽象工厂强调一系列产品对象(简单或复杂)。 Builder将产品作为最后一步返回,但就抽象工厂而言,产品会立即返回。
- Builder经常构build一个Composite。
- 通常情况下,devise开始使用工厂方法(更复杂,更可定制的子类泛化),并向devise师发现需要更多灵活性的抽象工厂,原型或构build器(更灵活,更复杂)。
- 有时创build模式是互补的:Builder可以使用其他模式来实现构build哪些组件。 Abstract Factory,Builder和Prototype可以在其实现中使用Singleton。
工厂devise模式的维基百科条目: http : //en.wikipedia.org/wiki/Factory_method_pattern
维基百科条目的build设者devise模式: http : //en.wikipedia.org/wiki/Builder_pattern
Factory模式几乎可以看作是Builder模式的简化版本。
在工厂模式中,工厂负责根据需要创build对象的各种子types。
工厂方法的用户不需要知道该对象的确切子types。 一个工厂方法createCar
的例子可能会返回一个Ford
或Honda
types的对象。
在构build器模式中,不同的子types也是由构build器方法创build的,但是对象的组合可能在相同的子类中不同。
为了继续汽车的例子,你可能有一个createCar
构build方法,它创build一个4缸发动机的Honda
types的对象,或者一个6缸Honda
types的对象。 构build器模式允许更精细的粒度。
Builder模式和Factory方法模式的图表在Wikipedia上均可用。
工厂只是一个围绕构造函数的包装函数(可能是一个不同的类)。 关键的区别在于工厂方法模式需要在一个方法调用中构build整个对象,所有参数都在一行中传递。 最后的对象将被返回。
另一方面, 构build器模式本质上是一个包含所有可能的参数的包装器对象,您可能想要传递给构造器调用。 这使您可以使用setter方法来缓慢build立参数列表。 构build器类的另一个方法是build()方法,它只是将构build器对象传递到所需的构造器中,并返回结果。
在像Java这样的静态语言中,当你有一些(可能是可选的)参数时,这变得更加重要,因为它避免了对于所有可能的参数组合的伸缩构造函数的要求。 此外,构build器允许您使用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
构build器devise模式描述了一个知道如何在多个步骤中制作特定types的另一个对象的对象。 它在每个中间步骤中保持目标项目所需的状态。 想想StringBuilder是如何产生最终string的。
工厂devise模式描述了一个对象,该对象知道如何在一个步骤中创build多个不同但相关的对象types,其中根据给定的参数select特定的types。 考虑一下序列化系统,在那里你创build你的序列化器,并在一个负载调用中构造所需的对象。
-
逐步构build一个复杂的对象:构build器模式
-
一个简单的对象是通过使用单个方法创build的:工厂方法模式
-
使用多个工厂方法创build对象:抽象工厂模式
两者都是创build模式,创build对象。
1)工厂模式 – 假设你有一个超类和N个子类。 该对象的创build取决于传递哪个参数/值。
2)构build模式 – 创build复杂的对象。
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.
首先一些一般的事情要遵循我的论证:
devise大型软件系统的主要挑战是必须灵活而简单地进行改变。 出于这个原因,有一些指标如耦合和内聚。 为了实现可以轻松改变或扩展function的系统,而无需从头开始重新devise整个系统,可以遵循devise原则(如SOLID等)。 过了一段时间,一些开发人员认识到,如果他们遵循这些原则,那么类似的解决scheme也可以解决类似的问题。 那些标准的解决scheme原来是devise模式。
所以devise模式是支持你遵循一般的devise原则,以实现具有高度凝聚力的松耦合系统。
回答这个问题:
通过询问两种模式之间的区别,您必须问自己,哪种模式会使您的系统更加灵活。 每个模式都有自己的目的来组织你系统中类之间的依赖关系。
抽象工厂模式: GoF:“提供一个创build相关或依赖对象族的界面,而不指定具体的类。
这意味着什么:通过提供这样的接口,对每个家族产品的构造函数的调用被封装在工厂类中。 而且因为这是整个系统中这些构造函数被调用的唯一地方,所以你可以通过实现一个新的工厂类来改变你的系统。 如果您通过另一种方式交换工厂代表,您可以交换一整套产品,而无需触及大部分代码。
Builder模式: GoF:“将复杂对象的构build与其表示分开,以便相同的构build过程可以创build不同的表示。
这是什么意思:你把build筑的过程封装在另一个阶级,称为导演(GoF)。 该导演包含创build产品新实例的algorithm(例如,从其他部分组成复杂产品)。 为了创造整个产品的组成部分,导演使用build筑师。 通过更换导演中的生成器,您可以使用相同的algorithm创build产品,但是可以更改单个部件的表示forms(以及产品的表示forms)。 要扩展或修改产品表示forms的系统,您只需实现一个新的构build器类。
所以简而言之:抽象工厂模式的目的是交换一系列使用在一起的产品。 生成器模式的目的是封装创build产品的抽象algorithm,以便将其用于产品的不同表示。
在我看来,你不能说抽象工厂模式是build模者的大哥哥。 是的,他们都是创造性的模式,但模式的主要目的是完全不同的。
build筑师和工厂之间的一个惊人的差异,我可以做出如下
假设我们有一辆车
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); }
但是如果在创buildSeats时发生了一些exception? 你不会得到所有的对象//但是
假设你有如下的实现
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; } }
现在你可以像这样创build
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则逐个build立。
虽然,这取决于哪一个devise的需要。
这是一个创build模式,因为它用于控制类的实例化。 构build器模式用于创build具有组成部分的复杂对象,组成部分必须以相同顺序或使用特定algorithm创build。 被称为导演的外部类控制构造algorithm。
样品
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApp_Design_Patterns { class BuilderDesignPattern { static void Main(string[] args) { //create a constructor object to start building Kid aKid = new Kid(); aKid.Name = "Elizabeth"; //Elizabeth use Monkey mold to make a monkey Console.WriteLine("{0} start making a monkey", aKid.Name); AnimalBuilder builderA = new MonkeyBuilder(); aKid.MakeAnimal(builderA); builderA.aAnimal.ShowMe(); //Elizabeth use Kitten mold to make a kitten Console.WriteLine("{0} start making a kitten", aKid.Name); AnimalBuilder builderB = new KittenBuilder(); aKid.MakeAnimal(builderB); builderB.aAnimal.ShowMe(); Console.Read(); } } public abstract class AnimalBuilder { public Animal aAnimal; public abstract void BuildAnimalHeader(); public abstract void BuildAnimalBody(); public abstract void BuildAnimalLeg(); public abstract void BuildAnimalArm(); public abstract void BuildAnimalTail(); } public class MonkeyBuilder : AnimalBuilder { public MonkeyBuilder() { aAnimal = new Monkey(); } public override void BuildAnimalHeader() { aAnimal.Head = "Moneky's Head has been built"; } public override void BuildAnimalBody() { aAnimal.Body = "Moneky's Body has been built"; } public override void BuildAnimalLeg() { aAnimal.Leg = "Moneky's Leg has been built"; } public override void BuildAnimalArm() { aAnimal.Arm = "Moneky's Arm has been built"; } public override void BuildAnimalTail() { aAnimal.Tail = "Moneky's Tail has been built"; } } public class KittenBuilder : AnimalBuilder { public KittenBuilder() { aAnimal = new Kitten(); } public override void BuildAnimalHeader() { aAnimal.Head = "Kitten's Head has been built"; } public override void BuildAnimalBody() { aAnimal.Body = "Kitten's Body has been built"; } public override void BuildAnimalLeg() { aAnimal.Leg = "Kitten's Leg has been built"; } public override void BuildAnimalArm() { aAnimal.Arm = "Kitten's Arm has been built"; } public override void BuildAnimalTail() { aAnimal.Tail = "Kitten's Tail has been built"; } } public abstract class Animal { public string Head { get; set; } public string Body { get; set; } public string Leg { get; set; } public string Arm { get; set; } public string Tail { get; set; } //helper method for demo the Polymorphism, so we can //easily tell what type object it is from client. public abstract void Eat(); //helper method for demo the result from client public void ShowMe() { Console.WriteLine(Head); Console.WriteLine(Body); Console.WriteLine(Leg); Console.WriteLine(Arm); Console.WriteLine(Tail); Eat(); } } public class Monkey : Animal { //helper method to show monkey's property for demo purpose public override void Eat() { Console.WriteLine("Since I am Monkey, I like to eat banana"); } } public class Kitten : Animal { public override void Eat() { Console.WriteLine("Since I am Kitten, I like to eat kitten food"); } } public class Kid { public string Name { get; set; } //construct process to build an animal object, //after this process completed, a object //will be consider as a ready to use object. public void MakeAnimal(AnimalBuilder aAnimalBuilder) { aAnimalBuilder.BuildAnimalHeader(); aAnimalBuilder.BuildAnimalBody(); aAnimalBuilder.BuildAnimalLeg(); aAnimalBuilder.BuildAnimalArm(); aAnimalBuilder.BuildAnimalTail(); } } }
抽象工厂&build造者模式都是创造性的模式,但有不同的意图。
抽象工厂模式强调为相关对象的家族创build对象,其中:
- 每个系列是从一个公共基类/接口派生的一组类。
- 每个对象都是作为一个调用的结果立即返回的。
构build器模式着重于逐步构build一个复杂的对象。 它将表示与构build复杂对象的过程分离开来,使得相同的构造过程可以用于不同的表示。
- Builder对象封装了复杂对象的configuration。
- Director对象知道使用Builder的协议,协议定义了构build复杂对象所需的所有逻辑步骤。
build设者和抽象工厂意味着不同的目的。 根据正确的使用情况,您必须select合适的devise模式。
生成器显着特点:
- Builder模式使用简单的对象构build一个复杂的对象,并使用一步一步的方法
- 一个Builder类逐步构build最终的对象。 这个构build器是独立于其他对象的
- 在这种情况下replace为工厂方法/抽象工厂:从客户端程序传递给Factory类的参数太多,可能会出错
- 一些参数可能是可选的,与Factory强制发送所有参数不同
工厂 (简易工厂)显着特点:
- 创造性的模式
- 基于inheritance
- 工厂返回一个工厂方法(接口),然后返回具体对象
- 你可以用新的具体对象代替接口,客户端(调用者)不应该知道所有具体的实现
- 客户端只能访问接口,您可以在Factory方法中隐藏对象创build细节。
通常情况下,devise开始使用工厂方法 (更复杂,更可定制的子类扩展),并演化为抽象工厂 , 原型或构build器 (更灵活,更复杂)
看看相关的post:
保持build设者在单独的类(stream畅的界面)
devise模式:工厂vs工厂方法与抽象工厂
你可以参考下面的文章了解更多细节:
sourcemaking
journaldev
两者都非常相似,但如果您有大量参数用于创build对象,其中某些参数可以使用某些默认值,请参阅构build器模式。
构build模式强调创build对象的复杂性 (由“步骤”解决)
抽象模式强调(多重但相关)对象的“抽象”。
区别明确在构build器模式中,构build器将为您创build特定types的对象。 你必须告诉build设者必须build立什么。 在工厂模式中,使用抽象类直接构build特定的对象。
这里,builder类充当主类和特定types类之间的中介。 更抽象。
我相信,Factory&Builder模式的使用和区别可以在一定时间段内更容易理解/澄清,因为您在相同的代码库和不断变化的需求上工作。
根据我的经验,通常情况下,你从一个工厂模式开始,包括几个静态创build者方法。 随着对象层次结构变得越来越复杂(或者添加更多types),您最终可能会使用更多的参数填充您的方法,更不用说您必须重新编译Factory模块。 所有这些都会增加创build者方法的复杂性,降低可读性并使创build模块更加脆弱。
这一点可能会成为转折点。 从工厂到生成器模式的转换。 通过这样做,您可以在构造参数周围创build一个包装模块,然后通过添加更多的抽象(可能)和实现而不触及实际的创build逻辑来表示新的(类似的)对象。 所以你已经不太复杂的逻辑和重新编译的源代码
坦率地说,提到某种“有一个步骤或多个步骤创造的对象是差异”,因为唯一的多样性因素不足以让我区分它们,因为我几乎可以同时使用所有我遇到的情况现在没有经历任何好处。 所以这是我终于想到的。
抽象工厂与build造者类似,也可以构build复杂的对象。 主要区别在于Builder模式着重于逐步构build一个复杂的对象。 抽象因素的重点是产品对象的家族(简单或复杂)。
build造者和抽象工厂
Builderdevise模式在某种程度上与Abstract Factory模式非常相似。 这就是为什么能够区分使用哪一种情况的原因。 在抽象工厂的情况下,客户使用工厂的方法来创build自己的对象。 在生成器的情况下,Builder类将被指示如何创build对象,然后被请求它,但类被放在一起的方式取决于Builder类,这个细节使两个模式之间的差异成为可能。
产品的通用界面
在实践中,由混凝土build造者创造的产品具有明显不同的结构,所以如果没有理由将不同的产品派生成共同的父类。 这也将Builder模式与创build从通用types派生的对象的抽象工厂模式区分开来。
来自: http : //www.oodesign.com/builder-pattern.html
在我看来,当你想从一堆其他对象创build一个对象时使用Builder模式,创build部件需要独立于你想创build的对象。 它有助于隐藏客户的一部分创造,使build设者和客户独立。 它用于复杂的对象创build(可能包含复杂属性的对象)
虽然工厂模式指定您要创build一个共同的家庭的对象,并希望它立即被消除。 它用于简单的对象。
工厂模式在运行时创build一个类的具体实现,即它的主要目的是使用多态来允许子类决定哪个类实例化。 这意味着在编译时我们不知道将要创build的确切的类,而构造器模式主要是解决由于一个类的大量可选字段而产生的伸缩构造函数反模式的问题。 在构build器模式中,没有多态的概念,因为我们知道在编译时我们想要构造什么对象。
这两种模式的唯一共同主题是隐藏工厂方法背后的构造函数和对象创build,以及构build方法,以改进对象构造。
工厂模式让你一次创build一个对象,而build造者模式让你打破一个对象的创build过程。 通过这种方式,可以在创build对象的过程中添加不同的function。
这两种模式都具有相同的必要性:从某些客户端代码隐藏复杂对象的构build逻辑……但是是什么使得“复杂”(或者有时使对象复杂化)一个对象? 主要是由于依赖关系,或者说是由更多的部分状态组成的对象的状态。 您可以通过构造函数注入依赖来设置初始对象状态,但是一个对象可能需要很多对象,有些对象会处于默认初始状态(仅仅是因为我们应该知道将默认依赖关系设置为null并不是最清洁的方式)和其他一些设置为由某种条件驱动的状态。 此外,还有一些对象属性是某种“不经意的依赖”,也可以是可选的状态
有两种众所周知的方式来控制这种复杂性:
- 合成/聚合:构造一个对象,构造它的依赖对象,然后连线到对象。 这里build设者可以使透明和灵活的过程决定了组件构build的规则
- 多态性:构造规则直接声明为子types定义,所以每个子types都有一组规则,而某些条件决定了这些规则集中的哪一个适用于构造该对象。 在这种情况下,工厂完全适合
没有什么可以阻止混合这两种方法。 一个产品族可以用构build器抽象创build对象,构build器可以使用工厂来确定哪个组件对象实例化
生成器模式和工厂模式似乎相同,因为它们都为您创build对象。
你需要仔细观察
这个现实生活中的例子会使两者更加清晰。
你去了快餐店,你点了食物 。
1)什么食物?
比萨
2)什么浇头?
辣椒,番茄,烧烤鸡,没有PINEAPPLE
所以不同types的食物是由工厂模式制成的,但是特定食物的不同变体是由build造者模式制成的。
不同种类的食物 – >比萨饼,汉堡,意大利面
披萨变种 – >只有奶酪,奶酪+番茄+辣椒,奶酪+番茄等
您可以在这里看到这两种模式的示例代码实现
build造者模式
工厂模式
恕我直言
Builder是一种更复杂的工厂。
但在Builder中,您可以使用另一个工厂实例化对象 ,这些工具是构build最终有效对象所必需的。
所以,通过复杂性来谈论“创造性模式”的演变,你可以这样思考:
Dependency Injection Container -> Service Locator -> Builder -> Factory
一个例子
1)使用抽象工厂:
GUIFactory factory = new WindowsGUIFactory(); Button button = factory.createButton(); // **creates a WindowsButton**
2)使用build造者:
GUIBuilder builder = new WindowsGUIBuilder(); Button button = builder.createButton(); // **creates a Button.** button.setOS = OSEnum.Windows;
由于没有WindowsButton类,他(构build者)必须负责正确构buildbutton,即: button.setOS = windows
。
这与在dbdevise中比较TPH与TPT类似。