How to use Builder Pattern in C#
By FoxLearn 12/27/2024 9:53:49 AM 635
It allows the creation of various types and representations of an object using the same construction process, promoting flexibility and separation of concerns in object creation.
Structure
Classes and objects that participate in this pattern include:
- Builder: Specifies an abstract interface by creating a part of the Product object.
- ConcreteBuilder: structure and pair parts of one product by implementing the Builder interface. redefine and record the details it creates. Provide an interface that can return the product details created.
- Director: create the object using the Builder interface
- Product: is a complex object created. ConcreteBuilder builds internal product details and defines pairing handling, including classes that define details, and interfaces to concatenate parts that produce the final result.
How to Implement Builder Pattern in C#?
public static void Main() { Director director = new Director(); Builder b1 = new ConcreteBuilder1(); Builder b2 = new ConcreteBuilder2(); director.Construct(b1); Product p1 = b1.GetResult(); p1.Show(); director.Construct(b2); Product p2 = b2.GetResult(); p2.Show(); } class Director { public void Construct(Builder builder) { builder.BuildPartA(); builder.BuildPartB(); } } abstract class Builder { public abstract void BuildPartA(); public abstract void BuildPartB(); public abstract Product GetResult(); } class ConcreteBuilder1 : Builder { private Product _product = new Product(); public override void BuildPartA() { _product.Add("PartA"); } public override void BuildPartB() { _product.Add("PartB"); } public override Product GetResult() { return _product; } } class ConcreteBuilder2 : Builder { private Product _product = new Product(); public override void BuildPartA() { _product.Add("PartX"); } public override void BuildPartB() { _product.Add("PartY"); } public override Product GetResult() { return _product; } } class Product { private List<string> _parts = new List<string>(); public void Add(string part) _parts.Add(part); public void Show() { Console.WriteLine("\nProduct Parts -------"); foreach (string part in _parts) Console.WriteLine(part); } }
This example will demonstrate the concept of separating the construction process into multiple parts, providing a builder pattern for complex product creation.
1. Define the Products (House and HouseManual)
House
represents the actual product, while HouseManual
is a manual for the house that describes its features.
public class House { public int Floors { get; set; } public int Bedrooms { get; set; } public bool HasGarage { get; set; } public bool HasGarden { get; set; } } public class HouseManual { public string Description { get; set; } }
2. Define the Builder Interface
IBuilder
defines the common methods for building the products.
public interface IBuilder { void Reset(); void SetFloors(int floors); void SetBedrooms(int bedrooms); void SetGarage(bool hasGarage); void SetGarden(bool hasGarden); object GetProduct(); }
3. Concrete Builder for House Construction
HouseBuilder
constructs a House
object, while HouseManualBuilder
constructs a HouseManual
object.
public class HouseBuilder : IBuilder { private House _house; public HouseBuilder() { Reset(); } public void Reset() { _house = new House(); } public void SetFloors(int floors) { _house.Floors = floors; } public void SetBedrooms(int bedrooms) { _house.Bedrooms = bedrooms; } public void SetGarage(bool hasGarage) { _house.HasGarage = hasGarage; } public void SetGarden(bool hasGarden) { _house.HasGarden = hasGarden; } public object GetProduct() { House product = _house; Reset(); return product; } }
4. Concrete Builder for House Manual
public class HouseManualBuilder : IBuilder { private HouseManual _manual; public HouseManualBuilder() { Reset(); } public void Reset() { _manual = new HouseManual(); } public void SetFloors(int floors) { _manual.Description += $"Floors: {floors}\n"; } public void SetBedrooms(int bedrooms) { _manual.Description += $"Bedrooms: {bedrooms}\n"; } public void SetGarage(bool hasGarage) { _manual.Description += $"Garage: {(hasGarage ? "Yes" : "No")}\n"; } public void SetGarden(bool hasGarden) { _manual.Description += $"Garden: {(hasGarden ? "Yes" : "No")}\n"; } public object GetProduct() { HouseManual product = _manual; Reset(); return product; } }
5. The Director Class
The Director
class uses the builder objects to construct products in a specific order. It doesn't know the specifics of the products, only how to construct them with the builder methods.
public class Director { public void ConstructBasicHouse(IBuilder builder) { builder.Reset(); builder.SetFloors(1); builder.SetBedrooms(2); builder.SetGarage(true); builder.SetGarden(true); } public void ConstructLuxuryHouse(IBuilder builder) { builder.Reset(); builder.SetFloors(3); builder.SetBedrooms(5); builder.SetGarage(true); builder.SetGarden(true); } }
6. Client
In the Application
class, the client interacts with the director and builders to construct either a house or its manual.
public class Application { public void BuildHouse() { Director director = new Director(); // Build a basic house HouseBuilder houseBuilder = new HouseBuilder(); director.ConstructBasicHouse(houseBuilder); House house = (House)houseBuilder.GetProduct(); Console.WriteLine($"House created with {house.Floors} floors, {house.Bedrooms} bedrooms, " + $"{(house.HasGarage ? "with" : "without")} a garage, " + $"{(house.HasGarden ? "with" : "without")} a garden."); // Build a luxury house manual HouseManualBuilder manualBuilder = new HouseManualBuilder(); director.ConstructLuxuryHouse(manualBuilder); HouseManual manual = (HouseManual)manualBuilder.GetProduct(); Console.WriteLine($"House Manual: \n{manual.Description}"); } }
The Builder pattern is especially useful when you need to create complex products (like houses) with many possible configurations (e.g., number of floors, garden, garage) and avoid cluttering the main product class (e.g., House
) with a large constructor. The pattern helps separate the construction logic and product representation, making it easier to maintain and modify.