Hôm nay, chúng ta sẽ tìm hiểu về Builder Design Pattern trong Java (mẫu thiết kế Builder). Đây là một mẫu dạng khởi tạo (creational), tương tự như các mẫu Factory và Abstract.

Mẫu này ra đời nhằm giải quyết một số vấn đề của Factory và Abstract, đặc biệt khi một đối tượng chứa nhiều thuộc tính. Có ba vấn đề chính thường gặp với các mẫu thiết kế trong trường hợp đối tượng có nhiều thuộc tính:
- Phải truyền quá nhiều tham số từ chương trình client đến class Factory. Điều này dễ gây ra lỗi vì kiểu dữ liệu của các tham số thường giống nhau, khiến phía client khó đảm bảo đúng thứ tự của chúng.
- Một số tham số có thể là không bắt buộc (optional), nhưng với Factory pattern, ta vẫn phải truyền vào đầy đủ. Đối với các tham số không bắt buộc này, ta phải truyền giá trị
NULL. - Nếu việc khởi tạo một object phức tạp và tốn nhiều tài nguyên, toàn bộ logic phức tạp đó sẽ nằm trong các class Factory, khiến chúng trở nên rối rắm và khó hiểu.
Ta có thể giải quyết vấn đề số lượng tham số lớn bằng cách cung cấp một constructor (phương thức khởi tạo) chỉ chứa các tham số bắt buộc, sau đó dùng các phương thức setter (phương thức gán giá trị cho thuộc tính) để gán giá trị cho các tham số tùy chọn. Tuy nhiên, vấn đề của cách tiếp cận này là trạng thái của đối tượng sẽ không nhất quán cho đến khi tất cả các thuộc tính được thiết lập một cách tường minh.
Mẫu Builder giải quyết vấn đề với số lượng lớn tham số tùy chọn và trạng thái không nhất quán bằng cách cung cấp một phương pháp xây dựng đối tượng theo từng bước, và cuối cùng sẽ cung cấp một phương thức để trả về đối tượng hoàn chỉnh.
Mẫu thiết kế Builder trong Java
Hãy cùng xem cách triển khai Builder pattern trong Java.
- Đầu tiên, ta cần tạo một lớp static lồng nhau (nested) rồi sao chép tất cả các thuộc tính từ lớp bên ngoài vào lớp Builder này. Ta nên tuân theo quy ước đặt tên: nếu lớp chính tên là
Computer, thì lớp builder nên có tên làComputerBuilder. - Lớp Builder trong Java nên có một constructor dạng public với các tham số là những thuộc tính bắt buộc.
- Lớp Builder trong Java nên có các phương thức để thiết lập những tham số tùy chọn. Mỗi phương thức này sau khi gán giá trị xong sẽ trả về chính đối tượng Builder đó.
- Bước cuối cùng là cung cấp một phương thức
build()trong lớp builder để trả về đối tượng mà chương trình client cần. Để làm được điều này, lớp chính cần có một constructor dạng private và nhận chính lớp Builder làm tham số.
Dưới đây là một chương trình ví dụ có lớp Computer cùng với lớp ComputerBuilder để tạo ra nó.
package com.journaldev.design.builder;
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;
}
//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 ý rằng lớp Computer chỉ có các phương thức getter (lấy tham số) và không có constructor dạng public. Vì vậy, cách duy nhất để có được một đối tượng Computer là thông qua lớp ComputerBuilder.
Dưới đây là một chương trình mẫu cho thấy cách sử dụng lớp Builder để lấy đối tượng.
package com.journaldev.design.test;
import com.journaldev.design.builder.Computer;
public class TestBuilderPattern {
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();
}
}
Ví dụ về mẫu Builder trong JDK
Một số class của Java sử dụng mẫu thiết kế Builder bao gồm:
java.lang.StringBuilder#append()(không đồng bộ)java.lang.StringBuffer#append()(đồng bộ)
Tổng kết
Hy vọng bài viết đã giúp bạn hiểu rõ hơn về cách áp dụng Builder Design Pattern trong Java để xây dựng các đối tượng phức tạp một cách hiệu quả và an toàn. Nếu bạn có thắc mắc hay cần giải thích thêm về bất kỳ phần nào, đừng ngần ngại đặt câu hỏi bên dưới nhé.