Builder Pattern – Code ví dụ Builder Pattern bằng Java.

Builder Pattern – Code ví dụ Builder Pattern bằng Java.

Builder Pattern là một mẫu thiết kế tạo dựng (Creation Pattern). Builder Pattern được xây dựng để khắc phục một số nhược điểm của Factory Pattern và Abstract Factory Pattern.

1. Builder Pattern

Builder pattern được sử dụng để xử lý các vấn đề còn tồn tại với  Factory Pattern và Abstract Factory Pattern khi mà Object có nhiều thuộc tính.

Có ba vấn đề chính với  Factory Pattern và Abstract Factory Pattern khi Object có nhiều thuộc tính:

  • Quá nhiều tham số phải truyền vào từ phía client tới Factory Class
  • Một số tham số có thể là tùy chọn nhưng trong Factory Pattern, chúng ta phải gửi tất cả tham số, với tham số tùy chọn nếu ko nhập gì thì sẽ truyền là null.
  • Nếu một Object có quá nhiều thuộc tính thì việc tạo sẽ phức tạp.

Chúng ta có thể sử lý những vấn đề này với một số lượng lớn các tham số bằng việc cung cấp một hàm khởi tạo với những tham số bắt buộc và các method getter/setter để cài đặt các tham số tùy chọn. Vấn đề với hướng tiếp cận này là trạng thái của Object sẽ không nhất quán cho tới khi tất cả các thuộc tính được cài đặt một cách rõ ràng

Builder pattern xử lý các vấn đề này bằng việc cung cấp một cách xây dựng đối tượng từng bước một và cung cấp một method để trả về đối tượng cuối cùng.

Một số ví dụ sử dụng Builder Pattern trong JDK:

  • java.lang.StringBuilder#append() (unsynchronized)
  • java.lang.StringBuffer#append() (synchronized)

2. Builder Pattern UML Diagram.

Builder Pattern – Code ví dụ Builder Pattern bằng Java.

Trong đó:

  • Product là đối tượng cần tạo (đối tượng này phức tạp, có nhiều thuộc tính)
  • Builder là abstract class hoặc interface khai báo phương thức tạo đối tượng
  • ConcreteBuilder thừa kế builder và cài đặt chi tiết cách tạo ra đối tượng.
  • Director là nơi sẽ gọi tới Builder để tạo ra đối tượng.

Thông thường, những trường hợp đơn giản người ta sẽ gộp luôn BuilderConcreteBuilder thành static nested class bên trong Product

3. Ví dụ

  • Tạo một static nested class (đây được gọi là builder class) và copy tất cả các tham số từ class bên ngoài vào. Chúng ta nên đặt tên của static nested class này theo định dạng tên class + Builder. Ví dụ class là Computer thì builder class sẽ là ComputerBuilder.
  • Class Builder có một hàm khởi tạo public với tất cả các thuộc tính bắt buộc.
  • Class Builder có các method setter cho các tham số tùy chọn.
  •  Cung cấp method build() trong Class Builder để trả về đối tượng mà client cần.
public class Computer {

  // required parameters
  private String HDD;
  private String RAM;

  // optional parameters
  private boolean isGraphicsCardEnabled;
  private boolean isBluetoothEnabled;

  public String getHDD() {
    return HDD;
  }

  public String getRAM() {
    return RAM;
  }

  public boolean isGraphicsCardEnabled() {
    return isGraphicsCardEnabled;
  }

  public boolean isBluetoothEnabled() {
    return isBluetoothEnabled;
  }

  private Computer(ComputerBuilder builder) {
    this.HDD = builder.HDD;
    this.RAM = builder.RAM;
    this.isGraphicsCardEnabled = builder.isGraphicsCardEnabled;
    this.isBluetoothEnabled = builder.isBluetoothEnabled;
  }


  @Override
  public String toString() {
    return "Computer [HDD=" + HDD + ", RAM=" + RAM + ", isGraphicsCardEnabled=" + isGraphicsCardEnabled
        + ", isBluetoothEnabled=" + isBluetoothEnabled + "]";
  }



  // Builder Class
  public static class ComputerBuilder {

    // required parameters
    private String HDD;
    private String RAM;

    // optional parameters
    private boolean isGraphicsCardEnabled;
    private boolean isBluetoothEnabled;

    public ComputerBuilder(String hdd, String ram) {
      this.HDD = hdd;
      this.RAM = ram;
    }

    public ComputerBuilder setGraphicsCardEnabled(boolean isGraphicsCardEnabled) {
      this.isGraphicsCardEnabled = isGraphicsCardEnabled;
      return this;
    }

    public ComputerBuilder setBluetoothEnabled(boolean isBluetoothEnabled) {
      this.isBluetoothEnabled = isBluetoothEnabled;
      return this;
    }

    public Computer build() {
      return new Computer(this);
    }

  }

}

 

Lưu ý là class Computer.java chỉ có method getter và không có hàm khởi tạo public nên chỉ có một cách duy nhất để lấy một đối tượng Computer là thông qua class ComputerBuilder.

Demo:

public class DemoBuilderPattern {
  public static void main(String[] args) {
    // Using builder to get the object in a single line of code and
    // without any inconsistent state or arguments management issues
    Computer comp = new Computer.ComputerBuilder("500 GB", "2 GB").setBluetoothEnabled(true)
        .setGraphicsCardEnabled(true).build();
    
    System.out.println(comp);
  }

}

Kết quả:

Computer [HDD=500 GB, RAM=2 GB, isGraphicsCardEnabled=true, isBluetoothEnabled=true]

 

Tương tự, thay vì tạo nested static class ComputerBuilder bên trong class Computer bạn có thể định nghĩa nó thành 1 class riêng như mô hình UML ở trên.

 

Thanks các bạn đã theo dõi. Xem thêm các ví dụ khác về design pattern tại: https://stackjava.com/category/design-pattern

References:

https://www.journaldev.com/1425/builder-design-pattern-in-java

https://www.javaworld.com/article/2074938/core-java/too-many-parameters-in-java-methods-part-3-builder-pattern.html

stackjava.com