.
Applicable scene
build a complex object
Pattern Role Composition
Abstract builder class (Builder): This interface stipulates the creation of those parts of the complex object, and does not involve the creation of specific component objects.
Concrete Builder Class (ConcreteBuilder): implements the Builder interface to complete the specific creation methods of each component of a complex product. After the construction process is complete, an instance of the product is provided.
Product class (Product): The complex object to be created.
Director class (Director): Call the specific builder to create each part of the complex object. The director does not involve the information of the specific product, and is only responsible for ensuring that the parts of the object are created completely or in a certain order.
Advantages and disadvantages
advantage:
The encapsulation of the builder pattern is very good. Using the builder mode can effectively encapsulate changes. In the scenario of using the builder mode, the general product class and the builder class are relatively stable. Therefore, encapsulating the main business logic in the commander class can achieve overall Relatively good stability.
In the builder mode, the client does not need to know the details of the internal composition of the product, and the product itself is decoupled from the product creation process, so that the same creation process can create different product objects.
The product creation process can be controlled more finely. Decomposing the creation steps of complex products into different methods makes the creation process clearer and more convenient to use programs to control the creation process.
The builder pattern is easy to extend. If there is a new requirement, it can be completed by implementing a new builder class, basically without modifying the code that has been tested before, so it will not introduce risks to the original function. Comply with the principle of opening and closing.
shortcoming:
The products created by the builder mode generally have more in common, and their components are similar. If the products are very different, it is not suitable to use the builder mode, so its scope of use is limited.
scenes to be used
The only difference between the builder pattern and the factory pattern is for the creation of complex objects. That is to say, if you create simple objects, you usually use the factory pattern to create them, and if you create complex objects, you can consider using the builder pattern.
When the product to be created has a complex creation process, the common creation process can be extracted, and then handed over to the specific implementation class to customize the creation process, so that the same creation behavior can produce different products, separate creation and presentation, and create products The flexibility is greatly increased.
The created object is complex and consists of multiple parts, each part faces complex changes, but the construction sequence between the components is stable.
The algorithm for creating a complex object is independent of the constituent parts of that object and how they are assembled, i.e. the construction process and final representation of the product are independent.
The Builder mode can be changed as needed during the application process. If there is only one type of product to be created and only one specific builder is needed, then the abstract builder can be omitted, and even the role of the commander can be omitted.
Differences from other creational design patterns
Factory method pattern VS builder pattern
The factory method pattern focuses on the creation of the overall object; while the builder pattern focuses on the process of component construction, intending to create a complex object through precise construction step by step.
Let's give a simple example to illustrate the difference between the two. If you want to make a superman, if you use the factory method model, you will directly produce a superman with infinite strength, ability to fly, and wear underwear; if you use the builder model, You need to assemble the hands, head, feet, torso and other parts, and then wear the underwear outside, so a superman was born.
Abstract Factory Pattern VS Builder Pattern
The abstract factory pattern realizes the creation of product families. A product family is such a series of products: a product combination with different classification dimensions. The abstract factory pattern does not need to care about the construction process, but only cares about which products are produced by which factories. .
The builder mode requires building products according to a specified blueprint, and its main purpose is to produce a new product by assembling spare parts.
If the abstract factory pattern is regarded as an auto parts production factory, which produces a product family of products, then the builder pattern is a car assembly factory, which can return a complete car through the assembly of parts.
code example
Book - Basic Edition (including Commander, Abstract Builder, Concrete Builder, etc.)
client
using DefaultBuilderPattern; using Newtonsoft.Json; Console.WriteLine("Hello, World!"); Console.WriteLine("=====Assembling a Lenovo PC======"); LenovoComputeBuilder lenovoComputeBuilder = new LenovoComputeBuilder(); Director director = new Director(lenovoComputeBuilder); var lenovoComputer = director.AssembleComputer(); Console.WriteLine($"The Ultimate Lenovo PC:{JsonConvert.SerializeObject(lenovoComputer)}"); Console.WriteLine("=====Assembling a Dell Computer======"); DellComputerBuilder dellComputeBuilder = new DellComputerBuilder(); director = new Director(dellComputeBuilder); var dellComputer = director.AssembleComputer(); Console.WriteLine($"The ultimate Dell computer:{JsonConvert.SerializeObject(lenovoComputer)}");
computer class
public class Computer { public string Cpu { get; set; } public string Memory { get; set; } public string Disk { get; set; } }
builder abstract class
public abstract class ComputeBuilderAbstract { protected Computer computer = new Computer(); public abstract void BuildCpu(); public abstract void BuildMemory(); public abstract void BuildDisk(); public Computer Build() => computer; }
Specific implementation classes (Lenovo computer assembly, Dell computer assembly)
public class LenovoComputeBuilder : ComputeBuilderAbstract { public override void BuildCpu() { computer.Cpu = "i7 8 nuclear"; Console.WriteLine("assembly i7 8 nuclear Cpu"); } public override void BuildDisk() { computer.Disk = "ASUS High Performance Gaming Motherboard HS23641"; Console.WriteLine("Assembling an ASUS high-performance gaming motherboard HS23641"); } public override void BuildMemory() { computer.Memory = "32GB"; Console.WriteLine("Assembly 32 GB RAM"); } } public class DellComputerBuilder : ComputeBuilderAbstract { public override void BuildCpu() { computer.Cpu = "i5 Processor 4 cores"; Console.WriteLine("assembly i5 Processor 4 cores Cpu"); } public override void BuildDisk() { computer.Disk = "MSI entry-level motherboard GB2365"; Console.WriteLine("Assembling an MSI entry-level motherboard GB2365"); } public override void BuildMemory() { computer.Memory = "4GB"; Console.WriteLine("Assembly 4 GB RAM"); } }
final effect
Omit the Commander Edition
It is mainly used when the builder is single, the construction process can be controlled by the client itself, and the commander has little effect
//---Omit the commander version Console.WriteLine("=====Omit the Commander Edition======"); DellComputerBuilder ignoredirectorComputeBuilder = new DellComputerBuilder(); ignoredirectorComputeBuilder.BuildDisk(); ignoredirectorComputeBuilder.BuildCpu(); ignoredirectorComputeBuilder.BuildMemory(); Console.WriteLine($"The ultimate Dell computer:{JsonConvert.SerializeObject(ignoredirectorComputeBuilder.Build())}");
final effect
Fluent style version
This method is suitable for stable and common behaviors in the construction process, such as assembling the computer in the article, where installing the motherboard, Cpu, and memory are all necessary steps for assembling the computer
public interface IComputerBuilder { IComputerBuilder BuildDisk(); IComputerBuilder BuildCpu(); IComputerBuilder BuildMemory(); Computer Build(); }
public class FluentLenovoComputeBuilder : IComputerBuilder { private Computer computer = null; public FluentLenovoComputeBuilder() { this.computer = new Computer(); } public IComputerBuilder BuildCpu() { computer.Cpu = "i7 8 nuclear"; Console.WriteLine("assembly i7 8 nuclear Cpu"); return this; } public IComputerBuilder BuildDisk() { computer.Disk = "ASUS High Performance Gaming Motherboard HS23641"; Console.WriteLine("Assembling an ASUS high-performance gaming motherboard HS23641"); return this; } public IComputerBuilder BuildMemory() { computer.Memory = "32GB"; Console.WriteLine("Assembly 32 GB RAM"); return this; } public Computer Build() { return computer; } }
The final effect is consistent with the above
Fluent style simple version
I personally like this one better. From the outermost Client calling code, the semantics are very clear. The abstract Builder interface is more pure and the granularity is smaller. It conforms to the principle of single and interface isolation. The overall code does not look bloated and easy to read. The disadvantage is that the entire construction The process needs to be controlled by yourself. If it is used improperly, the final constructed object may not be complete.
public interface IComputerBuilderB { Computer Build(); } public class FluentLenovoComputeBuilderB : IComputerBuilderB { private Computer computer = null; public FluentLenovoComputeBuilderB() { this.computer = new Computer(); } public FluentLenovoComputeBuilderB BuildCpu() { computer.Cpu = "i7 8 nuclear"; Console.WriteLine("assembly i7 8 nuclear Cpu"); return this; } public FluentLenovoComputeBuilderB BuildDisk() { computer.Disk = "ASUS High Performance Gaming Motherboard HS23641"; Console.WriteLine("Assembling an ASUS high-performance gaming motherboard HS23641"); return this; } public FluentLenovoComputeBuilderB BuildMemory() { computer.Memory = "32GB"; Console.WriteLine("Assembly 32 GB RAM"); return this; } public Computer Build() { return computer; } }
final rendering