Builder Pattern in C#

Giới thiệu

Trong bài trước thì mình đã giới thiệu về "Abstract Factory Pattern in C#", hôm nay thì mình xin tiếp tục giới thiệu về 1 pattern trong "Creational Patterns", đó chính là Builder Pattern.

Định nghĩa

Builder Pattern chia cấu trúc của 1 object phức tạp từ những chi tiết nhỏ của nó, vì vậy 1 xứ lý giống nhau có thể tạo ra những object với chi tiết khác nhau (nhờ những builder khác nhau) Độ sử dụng thường xuyên: Bình thường Để hiểu rõ hơn về pattern này thì chúng ta sẽ cùng xem giải thích và ví dụ nhé.

UML Diagram

Các thành phần

Các class và object tham gia vào pattern này bao gồm:

  • Builder (VehicleBuilder) cụ thế hóa 1 abstract interface bằng cách tạo ra 1 phần của Product object
  • ConcreteBuilder (MotorCycleBuilder, CarBuilder, ScooterBuilder)
  • cấu trúc và ghép nối các phần của 1 product bằng cách implement Builder interface
  • định nghĩa lại và ghi lại những chi tiết mà nó tạo ra
  • đưa ra 1 interface để có thể trả về chi tiết product tạo ra
  • Director (Shop) tạo ra object sử dụng Builder interface
  • Product (Vehicle) chính là object phức tạp được tạo ra. ConcreteBuilder xây dựng chi tiết sản phẩm bên trong và định nghĩa việc xử lý ghép nối, gồm các class định nghĩa các chi tiết, và các interface để ghép nối các phần tạo ra kết quả cuối cùng.

Cấu trúc code trong C#

using System;
using System.Collections.Generic;
 
namespace DoFactory.GangOfFour.Builder.Structural
{
  /// <summary>

  /// MainApp startup class for Structural

  /// Builder Design Pattern.

  /// </summary>

  public class MainApp

  {
    /// <summary>

    /// Entry point into console application.

    /// </summary>

    public static void Main()
    {
      // Create director and builders

      Director director = new Director();
 
      Builder b1 = new ConcreteBuilder1();
      Builder b2 = new ConcreteBuilder2();
 
      // Construct two products

      director.Construct(b1);
      Product p1 = b1.GetResult();
      p1.Show();
 
      director.Construct(b2);
      Product p2 = b2.GetResult();
      p2.Show();
 
      // Wait for user

      Console.ReadKey();
    }
  }
 
  /// <summary>

  /// The 'Director' class

  /// </summary>

  class Director

  {
    // Builder uses a complex series of steps

    public void Construct(Builder builder)
    {
      builder.BuildPartA();
      builder.BuildPartB();
    }
  }
 
  /// <summary>

  /// The 'Builder' abstract class

  /// </summary>

  abstract class Builder

  {
    public abstract void BuildPartA();
    public abstract void BuildPartB();
    public abstract Product GetResult();
  }
 
  /// <summary>

  /// The 'ConcreteBuilder1' class

  /// </summary>

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

  /// The 'ConcreteBuilder2' class

  /// </summary>

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

  /// The 'Product' class

  /// </summary>

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

Kết quả

Product Parts -------
PartA
PartB

Product Parts -------
PartX
PartY

Cấu trúc code trong dự án thực tế


using System;
using System.Collections.Generic;
 
namespace DoFactory.GangOfFour.Builder.RealWorld
{
  /// <summary>

  /// MainApp startup class for Real-World 

  /// Builder Design Pattern.

  /// </summary>

  public class MainApp

  {
    /// <summary>

    /// Entry point into console application.

    /// </summary>

    public static void Main()
    {
      VehicleBuilder builder;
 
      // Create shop with vehicle builders

      Shop shop = new Shop();
 
      // Construct and display vehicles

      builder = new ScooterBuilder();
      shop.Construct(builder);
      builder.Vehicle.Show();
 
      builder = new CarBuilder();
      shop.Construct(builder);
      builder.Vehicle.Show();
 
      builder = new MotorCycleBuilder();
      shop.Construct(builder);
      builder.Vehicle.Show();
 
      // Wait for user

      Console.ReadKey();
    }
  }
 
  /// <summary>

  /// The 'Director' class

  /// </summary>

  class Shop

  {
    // Builder uses a complex series of steps

    public void Construct(VehicleBuilder vehicleBuilder)
    {
      vehicleBuilder.BuildFrame();
      vehicleBuilder.BuildEngine();
      vehicleBuilder.BuildWheels();
      vehicleBuilder.BuildDoors();
    }
  }
 
  /// <summary>

  /// The 'Builder' abstract class

  /// </summary>

  abstract class VehicleBuilder

  {
    protected Vehicle vehicle;
 
    // Gets vehicle instance

    public Vehicle Vehicle
    {
      get { return vehicle; }
    }
 
    // Abstract build methods

    public abstract void BuildFrame();
    public abstract void BuildEngine();
    public abstract void BuildWheels();
    public abstract void BuildDoors();
  }
 
  /// <summary>

  /// The 'ConcreteBuilder1' class

  /// </summary>

  class MotorCycleBuilder : VehicleBuilder

  {
    public MotorCycleBuilder()
    {
      vehicle = new Vehicle("MotorCycle");
    }
 
    public override void BuildFrame()
    {
      vehicle["frame"] = "MotorCycle Frame";
    }
 
    public override void BuildEngine()
    {
      vehicle["engine"] = "500 cc";
    }
 
    public override void BuildWheels()
    {
      vehicle["wheels"] = "2";
    }
 
    public override void BuildDoors()
    {
      vehicle["doors"] = "0";
    }
  }
 
 
  /// <summary>

  /// The 'ConcreteBuilder2' class

  /// </summary>

  class CarBuilder : VehicleBuilder

  {
    public CarBuilder()
    {
      vehicle = new Vehicle("Car");
    }
 
    public override void BuildFrame()
    {
      vehicle["frame"] = "Car Frame";
    }
 
    public override void BuildEngine()
    {
      vehicle["engine"] = "2500 cc";
    }
 
    public override void BuildWheels()
    {
      vehicle["wheels"] = "4";
    }
 
    public override void BuildDoors()
    {
      vehicle["doors"] = "4";
    }
  }
 
  /// <summary>

  /// The 'ConcreteBuilder3' class

  /// </summary>

  class ScooterBuilder : VehicleBuilder

  {
    public ScooterBuilder()
    {
      vehicle = new Vehicle("Scooter");
    }
 
    public override void BuildFrame()
    {
      vehicle["frame"] = "Scooter Frame";
    }
 
    public override void BuildEngine()
    {
      vehicle["engine"] = "50 cc";
    }
 
    public override void BuildWheels()
    {
      vehicle["wheels"] = "2";
    }
 
    public override void BuildDoors()
    {
      vehicle["doors"] = "0";
    }
  }
 
  /// <summary>

  /// The 'Product' class

  /// </summary>

  class Vehicle

  {
    private string _vehicleType;
    private Dictionary<string,string> _parts = 
      new Dictionary<string,string>();
 
    // Constructor

    public Vehicle(string vehicleType)
    {
      this._vehicleType = vehicleType;
    }
 
    // Indexer

    public string this[string key]
    {
      get { return _parts[key]; }
      set { _parts[key] = value; }
    }
 
    public void Show()
    {
      Console.WriteLine("\n---------------------------");
      Console.WriteLine("Vehicle Type: {0}", _vehicleType);
      Console.WriteLine(" Frame : {0}", _parts["frame"]);
      Console.WriteLine(" Engine : {0}", _parts["engine"]);
      Console.WriteLine(" #Wheels: {0}", _parts["wheels"]);
      Console.WriteLine(" #Doors : {0}", _parts["doors"]);
    }
  }
}

Kết quả:

---------------------------
Vehicle Type: Scooter
 Frame  : Scooter Frame
 Engine : none
 #Wheels: 2
 #Doors : 0

---------------------------
Vehicle Type: Car
 Frame  : Car Frame
 Engine : 2500 cc
 #Wheels: 4
 #Doors : 4

---------------------------
Vehicle Type: MotorCycle
 Frame  : MotorCycle Frame
 Engine : 500 cc
 #Wheels: 2
 #Doors : 0

Kết luận

Builder Pattern có mức độ sử dụng vừa phải và các bạn nên cân nhắc sử dụng để có thể làm cho code sạch sẽ và dễ nhìn. Cảm ơn các bạn đã đọc bài. Bài viết tham khảo từ nguồn: http://www.dofactory.com/net/builder-design-pattern

All Rights Reserved