Hello, Hello dạo gần đây khi làm việc tại công ty mới, mình nhận thấy mình code khá là "thủ công" đã được một ông anh làm cùng freelancer nhận xét là:

Đây cũng là lý do mình tạo ra series này với mục đích tự học và chia sẻ, cũng như giải thích các design partern.
Decorator
Dịch qua tiếng Việt mình thì nó là "trang trí" bên trong hoặc bên ngoài một "đối tượng"
Bài toán cụ thể:
Có một sản phẩm được sản xuất tại Hưng Yên có giá bán trong tỉnh là 100 đ, khi được giao đến thành phố Hà Nội với chi phí giao hàng là 50 đ. Nếu sản phẩm đó được gói lại như một món quà tặng thì phí thêm sẽ là 50 đ nữa.
Nếu là tôi trước đây thì sẽ code như sau:
class Product {
private int $price = 100;
public function withShip() {
$this->price += 50;
}
public function asAGift() {
$this->price += 50;
}
public fucntion getPrice() {
return $this->price;
}
}
$product = new Product;
$product->withShip();
$product->asAGift();
echo $product->getPrice();Trông khá là clean đúng không nào ? Nhưng nó đang vi phạm SOLID rồi. Cụ thể ở đây là O – Open/Close tham khảo tại SOLID PRINCIPLES
Giờ thì ta làm các nào, mà mai sau nếu tôi bán thêm món nữa đó là cây cảnh, đó là bún, phở, cơm ... thì tôi lại viết lại hết các function ở dưới à ? Nếu chi phí vận chuyển, giấy gói quà thay đổi thì tôi phải sửa lại hết à ? hay nhét vào Const dùng cho cả hệ thống. Vậy nếu thay đổi logic giao hàng hay logic gói quà thì sao ? Quá nhiều thứ nếu chúng ta viết thế này sẽ khó maintain về sau.
Giải pháp
Tạo ra 1 interface Product có hàm tính phí (getPrice). Interface này có nhiệm vụ duy nhất là tính phí và mọi class khác khi implements Interface đều có thể có giá, có thể ship...
Class Product là class nền tảng có nhiệm vụ tính phí cho sản phẩm nguyên bản. Giá gốc của sản phẩm đó.

Giờ thêm 1 class WithShippingFee như vậy nữa. Cách sử dụng sẽ là như sau:

Giờ tôi sẽ thêm một class phụ trách việc tính phí gói quà nhé

Giờ tôi sẽ bán thêm một món nữa là cây cảnh hoặc đồ ăn...

Đó, bạn thấy giờ code rất rõ ràng, dễ maintain. Sau nếu có logic gì liên quan đến giá thì tôi sẽ sửa ở đây, thêm logic ship đi HN 1 giá, HCM 1 giá mà chỉ sửa ở 1 nơi.
Design Partern vô cùng dễ học và dễ áp dụng vào nhiều bài toán. Chúng ta có thể dễ dàng nhận dạng chúng qua bằng các phương thức tạo(construct) hoặc hàm tạo (make, build, init ....) chấp nhận các đối tượng của cùng lớp(class) hoặc giao diện(interface) với lớp hiện tại.
Lợi ích và hạn chế của nó

Chúc bạn có ngày làm việc hiệu quả, mình sẽ liên tục cập nhật các thông tin về series này, mn cùng đón xem nhé.