Mẫu thiết kế decorator

Chắc hẳn các bạn đã từng nghe đến cụm từ Design pattern (Mẫu thiết kế)? Nếu như bạn chưa từng nghe nói đến nó, thì bạn vẫn chưa thực sự trở thành một lập trình viên.

Thực ra mình cũng nghe nói đến mẫu thiết kế từ lâu rồi, nhưng do lười học, và trình độ tiếng Anh hạn chế, trong khi tài liệu về mẫu thiết kế hầu hết đều là tiếng Anh, nên mình chưa thực sự hiểu sâu về Mẫu thiết kế.

Nhân tiện khoảng thời gian chăm chỉ hiếm hoi, mình học và viết lại để chia sẻ với các bạn về một số mẫu thiết kế thông dụng.

Trong phạm vi bài viết này mình sẽ nói về mẫu thiết kế decorator (mẫu trang trí). Nhưng trước tiên, chúng ta cần hiểu rõ mẫu thiết kế là gì?

Mẫu thiết kế (design pattern) là gì?

Mẫu thiết kế - chắc nhiều bạn sẽ cảm thấy thuật ngữ này có vẻ rất trừu tượng, khó hiểu, thiên về học thuật. Nhưng theo ý hiểu của mình, thì mẫu thiết kế đơn giản chỉ là kinh nghiệm, giải pháp giải quyết vấn đề trong lập trình hướng đối tượng.

Bạn hãy thử tưởng tượng, bạn có thể xây một căn nhà 2 tầng rất dễ dàng, xây xong tầng 2, nếu bạn thấy tầng 1 không vừa ý, ban có thể làm lại. Nhưng với ngôi nhà hàng trăm tầng thì sao, xây đến tầng 50 bạn mới nhận ra là chiếc móng không đủ để chịu tải cho 100 tầng, bạn có thể đập đi làm lại không?

Trong phát triển phần mềm cũng vậy, khi xây dựng hệ thống lớn có đến hàng vạn đối tượng, nếu không có chiến lược xây dựng, hệ thống của bạn sẽ khó có thể chạy tốt được.

Vì thế mẫu thiết kế ra đời. Mẫu thiết kế là tinh tuý, kết tinh mà hàng ngàn kĩ sư phần mềm giỏi nhất trên thế giới, trải qua rất nhiều dự án cả thành công lẫn thất bại đã đúc kết lại. Và bây giờ chúng ta chỉ cần học, hiểu và áp dụng vào dự án của mình.

Decorator pattern (Mẫu thiết kế trang trí)

Giả sử bạn là nhân viên quầy thanh toán của cửa hàng điện máy. Bạn có 1 chiếc máy tính để in ra hoá đơn đơn hàng. Mỗi lần in hoá đơn bạn phải nhập tất cả sản phẩm một lần.

Một hôm khách hàng đến mua chiếc máy tính, bạn in ra hoá đơn "Quý khách mua 1 chiếc máy tính".

Hoá đơn vừa in xong, khách hàng đổi ý, muốn mua thêm cái màn hình. Bạn phải huy hoá đơn cũ, in ra hoá đơn mới "Quý khách mua 1 chiếc máy tính và 1 chiếc màn hình".

Bạn vui vẻ đưa hoá đơn cho khách hàng, nhưng khách hàng lạị đổi ý, muốn mua thêm 1 con chuột.

Dù không vui, bạn vẫn phải in hoá đơn mới "Quý khách mua 1 chiếc máy tính và 1 chiếc màn hình và một con chuột".

Tưởng chừng như mọi chuyện sẽ dừng lại ở đây, nhưng không, khách hàng muốn mua thêm 1 chiếc bàn phím nữa.

Tôi cá là lúc này, bạn đã không còn đủ bình tĩnh để chiều "thượng đế" này nữa. Nhưng bạn vẫn phải in ra hoá đơn "Quý khách mua 1 chiếc máy tính và 1 chiếc màn hình và một con chuột và 1 chiếc bàn phím".

Thực ra khách hàng không có lỗi, mà là lỗi thiết kế của phần mềm in hoá đơn của bạn. Mẫu thiết kế decorator chính là giải pháp giải quyết vấn đề này.

Mẫu thiết kế decorator là mẫu thiết kế dùng để mở rộng đối tượng mà không cần thay đổi mã nguồn cũ trong đối tượng. Với nguyên tắc thiết kế đối tượng là "đóng cho việc sửa đổi và mở cho việc mở rộng".

Như vậy khi áp dụng mẫu thiết kế này, mã nguồn của bạn sẽ có tính mềm dẻo, tính mở rộng cao. Bạn có thể thêm mới, mở rộng lớp đối tượng mà không phải thay đổi mã nguồn cũ, sẽ giảm được thời gian kiểm thử.

Dưới đây là mã nguồn thực thi mẫu thiết kế decorator viết bằng javascript.

function DonHang() {
  this.print = function() {
    return "Quý khách mua";
  }
}

function MayTinh(donhang) {
  var desc = donhang.print();
  this.print = function() {
    return desc + " " + "1 chiếc máy tính";
  }
}

function ManHinh(donhang) {
  var desc = donhang.print();
  this.print = function() {
    return desc + " " + "và 1 chiếc màn hình";
  }
}

function Chuot(donhang) {
  var desc = donhang.print();
  this.print = function() {
    return desc + " " + "và một con chuột";
  }
}

function BanPhim(donhang) {
  var desc = donhang.print();
  this.print = function() {
    return desc + " " + "và một chiếc bàn phím";
  }
}

var donhang = new DonHang();
donhang = new MayTinh(donhang);
donhang = new ManHinh(donhang);
donhang = new Chuot(donhang);
donhang = new BanPhim(donhang);
donhang.print();

Để đơn giản, bạn hãy hình dung mẫu thiết kế decorator giống như bạn trang trí một món quà. Bạn đặt quà vào hộp, bọc giấy gói quà, viết thiệp và cho vào túi. Bạn đã biến một món đồ thành quà tặng mà không hề động đến món đồ đó. Đấy chính là ý nghĩa của từ decorator (người trang trí).

Kết luận

Bạn hãy nhớ nguyên lý: "Mở cho việc mở rộng và đóng cho việc sửa đổi".