Giới thiệu
Khi thiết kế các đối tượng phức tạp trong Java, đặc biệt là những đối tượng có nhiều tham số tùy chọn, Mẫu Thiết Kế Builder cung cấp một giải pháp sạch sẽ và linh hoạt. Thay vì sử dụng các hàm khởi tạo dài với hàng chục tham số (thường được gọi là vấn đề hàm khởi tạo dài), mẫu Builder giúp chúng ta tạo ra các đối tượng từng bước một cách dễ đọc.
- Trong bài viết này, chúng ta sẽ tìm hiểu:
- Vấn đề với việc tạo đối tượng truyền thống.
- Cách hoạt động của Mẫu Thiết Kế Builder.
- Một triển khai thực tế trong Java.
- Ưu điểm và các trường hợp sử dụng.
Vấn đề
Hãy tưởng tượng bạn đang xây dựng một lớp User với nhiều trường:
java
public class User {
private String firstName;
private String middleName;
private String lastName;
private int age;
private String email;
private String phone;
private String alternativePhone;
}
Bây giờ, hãy xem xét các kịch bản cho người dùng:
- Một người dùng chỉ có tên và họ mà không có tên đệm.
- Một người dùng không có số điện thoại thay thế.
- Một người dùng với tất cả các trường.
Nếu bạn cố gắng xử lý điều này bằng cách sử dụng các hàm khởi tạo, bạn sẽ kết thúc với nhiều hàm khởi tạo quá tải như:
java
User(String firstName, String lastName) { ... }
User(String firstName, String middleName, String lastName) { ... }
User(String firstName, String lastName, int age, String email, String phone) { ... }
User(String firstName, String lastName, int age, String email, String phone, String alternativePhone) { ... }
Cách tiếp cận này nhanh chóng trở nên lộn xộn và khó đọc.
Giải pháp: Mẫu Builder
Mẫu Builder tách biệt việc xây dựng một đối tượng phức tạp khỏi việc biểu diễn của nó, cho phép bạn tạo ra các đối tượng từng bước một.
java
public class User {
// Các trường bắt buộc
private final String firstName;
private final String lastName;
private final int age;
private final String email;
private final String phone;
// Các trường tùy chọn
private final String middleName;
private final String alternativePhone;
// Hàm khởi tạo riêng để đảm bảo việc tạo đối tượng thông qua Builder
private User(Builder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.middleName = builder.middleName;
this.age = builder.age;
this.email = builder.email;
this.phone = builder.phone;
this.alternativePhone = builder.alternativePhone;
}
// Lớp Builder lồng vào
public static class Builder {
private final String firstName;
private final String lastName;
private int age;
private String email;
private String phone;
private String alternativePhone;
// Hàm khởi tạo Builder với các trường bắt buộc
public Builder(String firstName, String lastName, int age, String email, String phone) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.email = email;
this.phone = phone;
}
// Các phương thức giống như setter cho các trường tùy chọn
public Builder middleName(String middleName) {
this.middleName = middleName;
return this;
}
public Builder alternativePhone(String alternativePhone) {
this.alternativePhone = alternativePhone;
return this;
}
// Phương thức build cuối cùng
public User build() {
return new User(this);
}
}
@Override
public String toString() {
return "User [firstName=" + firstName + ", lastName=" + lastName + ", middleName=" + middleName + ", age=" + age + ", email=" + email + ", phone=" + phone + ", alternativePhone=" + alternativePhone + "]";
}
}
Cách sử dụng:
java
public class Main {
public static void main(String[] args) {
User user1 = new User.Builder("John", "Doe", 30, "john.doe@example.com", "1234567890")
.middleName("Mario")
.build();
User user2 = new User.Builder("Alice", "Smith", 25, "alice@example.com", "1234567890")
.alternativePhone("4365354633")
.build();
System.out.println(user1);
System.out.println(user2);
}
}
Kết quả
User [firstName=John, middleName=Mario, lastName=Doe, age=30, email=john.doe@example.com, phone=1234567890, alternativePhone=null]
User [firstName=Alice, middleName=null, lastName=Smith, age=25, email=alice@example.com, phone=1234567890, alternativePhone=4365354633]
Ưu điểm của Mẫu Builder
✔️ Giúp việc xây dựng đối tượng trở nên dễ đọc và duy trì.
✔️ Xử lý các tham số tùy chọn một cách hợp lý.
✔️ Thúc đẩy tính bất biến (các đối tượng được tạo ra là không thay đổi).
✔️ Cung cấp phương pháp từng bước để xây dựng các đối tượng.
Khi nào nên sử dụng?
- Khi bạn có một lớp với nhiều tham số tùy chọn.
- Khi các hàm khởi tạo với nhiều tham số trở nên khó hiểu.
- Khi bạn muốn tạo các đối tượng bất biến một cách sạch sẽ.
Ví dụ thực tế
- StringBuilder trong Java (để xây dựng chuỗi từng bước).
- DocumentBuilder trong phân tích XML.
- Nhiều framework như Lombok, Jackson, và Spring sử dụng các builder nội bộ.
Kết luận
Mẫu Thiết Kế Builder là một trong những mẫu thiết kế sáng tạo mạnh mẽ và thường được sử dụng trong Java. Nó giúp mã nguồn trở nên dễ đọc, mở rộng và duy trì, đặc biệt là khi làm việc với các đối tượng phức tạp có thuộc tính tùy chọn.
Lần tới khi bạn thấy mình viết nhiều hàm khởi tạo hoặc gặp khó khăn với các tham số tùy chọn, hãy nghĩ đến Mẫu Builder!
Đây là Phần 5 trong chuỗi Mẫu Thiết Kế Java.
Nếu bạn thấy bài viết này hữu ích, hãy cho tôi biết ý kiến của bạn. Cũng cho tôi biết nếu bạn đã sử dụng mẫu builder trong các dự án của mình.
Chương tiếp theo: Mẫu Thiết Kế Cấu Trúc!