Menu
CoddyTech

Mẫu Builder

Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 67 trên 87.

Mẫu Builder là một mẫu thiết kế khởi tạo giúp giải quyết vấn đề phổ biến: tạo các đối tượng phức tạp với nhiều tham số tùy chọn. Thay vì tạo nhiều hàm khởi tạo hoặc truyền null cho các tham số không dùng đến, Builder cho phép bạn tạo đối tượng từng bước.

Hãy hình dung bạn cần tạo một đối tượng User với các trường bắt buộc (name, email) và các trường tùy chọn (age, phone, address). Nếu không dùng Builder, bạn sẽ cần các hàm khởi tạo lồng nhau hoặc một hàm khởi tạo rườm rà với nhiều tham số. Mẫu Builder mang đến cách làm gọn gàng hơn:

public class User {
    private final String name;    // bắt buộc
    private final String email;   // bắt buộc
    private final int age;        // không bắt buộc
    private final String phone;   // không bắt buộc
    
    private User(UserBuilder builder) {
        this.name = builder.name;
        this.email = builder.email;
        this.age = builder.age;
        this.phone = builder.phone;
    }
    
    public static class UserBuilder {
        private final String name;
        private final String email;
        private int age;
        private String phone;
        
        public UserBuilder(String name, String email) {
            this.name = name;
            this.email = email;
        }
        
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
        
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public User build() {
            return new User(this);
        }
    }
}

Các phương thức của Builder trả về this, cho phép nối chuỗi phương thức (method chaining): một cách liền mạch, dễ đọc để tạo đối tượng:

User user = new User.UserBuilder("Alice", "alice@email.com")
    .age(25)
    .phone("555-1234")
    .build();

Lưu ý rằng hàm khởi tạo của User là riêng tư: bạn chỉ có thể tạo đối tượng thông qua Builder. Mẫu này đặc biệt hữu ích khi đối tượng có nhiều trường tùy chọn, giúp code dễ đọc hơn và ít lỗi hơn so với danh sách tham số dài.

challenge icon

Thử thách

Dễ

Hãy cùng xây dựng hệ thống đặt pizza bằng mẫu thiết kế Builder (Builder Pattern)! Thay vì dùng một hàm khởi tạo có hàng tá tham số cho mọi loại nhân và tùy chọn có thể có, bạn sẽ tạo một builder linh hoạt, giúp tùy chỉnh pizza rõ ràng và dễ đọc.

Bạn sẽ sắp xếp code trong hai tệp:

  • Pizza.java: Tạo lớp Pizza sử dụng mẫu thiết kế Builder để khởi tạo. Pizza của bạn cần có các trường sau:

    size (String): bắt buộc, đại diện cho kích cỡ pizza

    cheese (boolean): không bắt buộc, mặc định là false

    pepperoni (boolean): không bắt buộc, mặc định là false

    mushrooms (boolean): không bắt buộc, mặc định là false

    Hàm khởi tạo của Pizza phải là private và chỉ nhận PizzaBuilder làm tham số, sau đó sao chép mọi giá trị từ builder vào các trường của pizza.

    Thêm phương thức getDescription() trả về một chuỗi theo định dạng này: [size] Pizza with: [toppings], trong đó toppings là danh sách các loại nhân được chọn, phân tách bằng dấu phẩy (Cheese, Pepperoni, Mushrooms). Nếu không chọn loại nhân nào, phần toppings chỉ cần ghi no toppings.

    Tạo lớp bên trong static PizzaBuilder gồm:

    • Hàm khởi tạo nhận tham số size bắt buộc
    • Các phương thức cheese(), pepperoni() và mushrooms(), mỗi phương thức đặt giá trị boolean tương ứng thành true và trả về this để có thể gọi nối tiếp
    • Phương thức build() trả về một đối tượng Pizza mới
  • Main.java: Hãy minh họa cách hoạt động của pizza builder! Bạn sẽ nhận bốn đầu vào: kích cỡ pizza (String) và ba giá trị có/không (String) cho biết lần lượt có thêm cheese, pepperoni và mushrooms hay không.

    Tạo một PizzaBuilder với kích cỡ đã cho. Sau đó, dựa trên từng đầu vào có/không, gọi nối tiếp các phương thức thêm nhân phù hợp. Nếu đầu vào là "yes", hãy gọi phương thức thêm nhân tương ứng; nếu là "no", hãy bỏ qua phương thức đó. Cuối cùng, gọi build() để tạo pizza.

    In kết quả gọi getDescription() trên pizza vừa tạo.

Bạn sẽ nhận lần lượt bốn đầu vào: size (String), add cheese (String: "yes" hoặc "no"), add pepperoni (String: "yes" hoặc "no"), add mushrooms (String: "yes" hoặc "no").

Ví dụ, với các đầu vào Large, yes, no, yes, đầu ra của bạn sẽ là: Large Pizza with: Cheese, Mushrooms

Hãy chú ý cách mẫu thiết kế Builder cho phép bạn tạo pizza với mọi tổ hợp nhân mà không cần viết hàm khởi tạo riêng cho từng trường hợp!

Tự làm thử

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Đọc các giá trị đầu vào
        String size = scanner.nextLine();
        String addCheese = scanner.nextLine();
        String addPepperoni = scanner.nextLine();
        String addMushrooms = scanner.nextLine();
        
        // TODO: Tạo PizzaBuilder với kích cỡ đã cho
        // TODO: Gọi nối tiếp các phương thức thêm nguyên liệu dựa trên đầu vào yes/no
        // TODO: Tạo bánh pizza và in ra mô tả của bánh
        
    }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Java online