Người thợ xây chăm chỉ!

Chúng ta hãy nhìn vào lớp MyOrder này:

public class MyOrder {

    private double money;

    public double getMoney() {
        return money;
    }
    public void setMoney(double money) {
        this.money = money;
    }
}

Giả sử chúng ta có 1 order với giá trị 1000:

MyOrder order = new MyOrder();
order.setMoney(1000);

Và có một lập trình viên nào đó đã say cafe và anh ta code thế này:

public class BillService {
    public void pay(MyOrder order) {
        order.setMoney(100000);
        payWithCreditCard(order.getMoney());
    }

    private void payWithCreditCard(double money) {
        System.out.println("user pay with credit card: " + money);
    }
}

Anh ta đã set lại giá của order là 100000, và thế là khách hàng sẽ lôi cả công ty ra kiện

Giới thiệu

Để tránh xảy ra những lỗi kiểu này, Builder pattern đã ra đời với 3 mục tiêu:

  1. Tạo ra các đối tượng immutable (không thay đổi được nội dung)
  2. Cho phép các lớp thừa kế quy định kiểu đối tượng sẽ được tạo ra
  3. Quy định một cách thức chung để giúp chúng ta tạo đối tượng mà không cần quan tâm đến hàm tạo, hay nói cách khác là không cần quan tâm đến thứ tự các tham số trong hàm tạo và loại bỏ việc phải sử dụng đa hàm tạo (telescoping constructor)

Ví dụ

Bây giờ hãy thay đổi lớp MyOrder một chút nhé:

public class MyOrder {

    private double money;

    public MyOrder(Builder builder) {
        this.money = builder.money;
    }

    public double getMoney() {
        return money;
    }

    public static class Builder {

        private double money;

        public Builder money(double money) {
            this.money = money;
            return this;
        }

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

Khi sử dụng sẽ thế này:

MyOrder order = new MyOrder.Builder()
    .money(1000)
    .build();

Và đoạn code này sẽ báo lỗi

public static class BillService {
        public void pay(MyOrder order) {
            order.setMoney(100000); // lỗi ở đây vì class MyOrder không có hàm setValue
            payWithCreditCard(order.getMoney());
        }
    }
}

Bạn thấy không, với sự biến mất của setMoney chúng ta có thể yên tâm đưa đối tượng order cho người khác sử dụng mà không sợ họ mắc sai lầm.

Tham khảo

  1. Lý thuyết
  2. Code ví dụ