“Add responsibilities to objects dynamicall”
Rules of thumb
– Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface.
– Adapter changes an object’s interface, Decorator enhances an object’s responsibilities. Decorator is thus more transparent to the client. As a consequence, Decorator supports recursive composition, which isn’t possible with pure Adapters.
– A Decorator can be viewed as a degenerate Composite with only one component. However, a Decorator adds additional responsibilities – it isn’t intended for object aggregation.
– Decorator is designed to let you add responsibilities to objects without subclassing. Composite’s focus is not on embellishment but on representation. These intents are distinct but complementary. Consequently, Composite and Decorator are often used in concert.
– Decorator and Proxy have different purposes but similar structures. Both describe how to provide a level of indirection to another object, and the implementations keep a reference to the object to which they forward requests.
– Decorator lets you change the skin of an object. Strategy lets you change the guts.
Download full source code use abstract class – CSharp
Download full source code use interface – CSharp
Giữ vững nguyên tắc viết mã “Open-Close” hay “Luôn mở cho việc mở rộng, nhưng đóng cho việc sửa đổi”
“Hôm nay có món gì?” bạn hỏi tay đầu bếp khó chịu đang đứng sau bếp nướng.
“Cho một cái hamburger,” bạn nói và xoay xoay cái khay trong tay.
Người đầu bếp mang cái hamburger đến bàn tính tiền, không quên hỏi lại “Có thêm thịt rán không?”
“Chắc chắn rồi”, bạn nói.
Người đầu bếp xóa phiếu ăn cũ trên máy tính tiền và làm lại phiếu ăn.
“Hamburger và thịt rán”. Vừa nói anh ta vừa gõ vào máy tính tiền.
“Cho thêm một ít pho mát” Bạn nói.
Người đầu bếp ném một ánh nhìn khó chịu , xóa cái phiếu ăn, mổ mổ cái bàn phím và nói “Hamburger với pho mát và thịt nướng. Ok. Đủ rồi chứ?”
“Hmm”, bạn nói, nhìn quét qua cái thực đơn “Hay là thêm một chút thịt xông khói?”
Người đầu bếp nhìn chằm chằm vào bạn và dường như định văng ra một vài câu khó chịu gì đó nhưng vẫn nhập phiếu ăn vào máy.
“Hey”, bạn nói. “Anh chắc chắn là được lợi nhiều hơn từ việc sử dụng mẫu thiết kế trang trí Decorator chứ hả?”
“Vâng”, anh đầu bếp trả lời, tự hỏi về những gì bạn nói “Tôi đã nói điều này cả ngàn lần rồi”
Bạn cầm cái Hamburger pho mát thịt xông khói với vẻ hạnh phúc và nói “Thêm một vài lát cà chua nữa thì tuyệt!”
Chương này nói về hai mẫu thiết kế quan trọng, nó sẽ lắp đầy những thiếu sót trong việc lập trình hướng đối tượng cơ bản, đặc biệt là ở khả năng kế thừa. Đây là hai mẫu trang trí Decorator và mẫu nhà máy Factory.
Mẫu trang trí Decorator là lựa chọn hoàn hảo cho tình huống tôi vừa nêu ở trên bởi vì ta đang nói về khả năng mở rộng chức năng cho một lớp có sẵn. Sau khi viết một lớp, bạn có thể thêm phần trang trí Decorator (các lớp mở rộng) để mở rộng lớp này. Khi đó bạn không phải sửa đổi lên lớp gốc. Kết quả là cái Hamburger của bạn trở thành Hamburger pho mát, rồi Hamburger pho mát thịt xông khói, mọi thứ thật dễ dàng.
Nguyên lý Open-Close – “Luôn Open cho việc mở rộng và Closed cho việc sửa đổi”
public class cComputer
{
public cComputer() { }
public string description()
{
return "You're getting a computer";
}
}
public class cComputer
{
public cComputer() { }
public string description()
{
return "You're getting a computer and a disk";
}
}
Bây giờ khi một đối tượng computer được tạo và bạn gọi phương thức description, bạn sẽ nhận được văn bản “You’re getting a computer and a disk.” Nhưng một vài khách hàng vẫn chưa hài lòng. Họ muốn thêm một cái màn hình nữa. Và thế là các lập trình viên phải chỉnh sửa tiếp như sau:
public class cComputer
{
public cComputer() { }
public string description()
{
return "You're getting a computer and a disk and a monitor";
}
}
Bây giờ, khi bạn tạo một computer và gọi phương thức description bạn sẽ thấy
"You're getting a computer and a disk and a monitor";
VÍ DỤ VỀ MẪU TRANG TRÍ DECORATOR
Example:
Bạn bắt đầu viết một lớp máy tính Computer đơn giản, với một phương thức description trả về kết quả “computer” như sau:
public class cComputer
{
public cComputer() { }
public string description()
{
return "computer";
}
}
Tạo dựng một Lớp trang trí Decorator
public interface IComputer
{
string description();
}
Thêm vào một đĩa cứng Disk
Đây là lớp bao bọc Disk , sẽ thêm một ổ cứng vào máy tính. Bởi vì đây là một lớp bao bọc, nó cần phải biết đang bao bọc thứ gì. Vì vậy bạn đưa cho nó một đối tượng computer ngay khi nó khởi tạo. Lớp bao bọc Disk sẽ lưu trữ một đối tượng tên computer
Bây giờ bạn cần hiện thực phương thức Description. Phương thức mới này sẽ gọi phương thức description của lớp computer và thêm vào dòng chữ “and a disk” như sau:
public class cDisk : IComputer
{
IComputer _icomp;
public cDisk(IComputer c)
{
_icomp = c;
}
public string description()
{
return _icomp.description() + " and a disk";
}
}
Vậy là bạn đã bao bọc đối tượng computer, và khi bạn gọi phương thức description của đối tượng disk này, nó sẽ gọi phương thức description của lớp computer, đồng thời thêm vào dòng chữ “and a disk”. Kết quả bạn sẽ có “computer and a disk”
Thêm vào một màn hình monitor
Tương tự với monitor
public class cMonitor : IComputer
{
IComputer _icomp;
public cMonitor(IComputer c)
{
_icomp = c;
}
public string description()
{
return _icomp.description() + " and a Monitor";
}
}
OK. Bạn đã có đầy đủ các lớp. Giờ là lúc chạy thử nghiệm chương trình.
Đầu tiên bạn tạo đối tượng computer như sau:
static void Main(string[] args)
{
IComputer comp = new cComputer(); // implements interface IComputer
Console.ReadLine();
}
Sau đó bạn bao bọc đối tượng computer để thêm vào một Monitor
static void Main(string[] args)
{
IComputer comp = new cComputer(); // implements interface IComputer
// add 1 Monitor
comp = new cMonitor(comp);
Console.ReadLine();
}
Bây giờ hãy thêm vào 2 Disk, Cuối cùng bạn gọi phương thức description của lớp bao bọc để xem kết quả:
static void Main(string[] args)
{
IComputer comp = new cComputer(); // implements interface IComputer
// add 1 Monitor
comp = new cMonitor(comp);
// and 2 Disk
comp = new cDisk(comp);
comp = new cDisk(comp);
Console.WriteLine(string.Format("you're getting: {0}" , comp.description()));
Console.ReadLine();
}
OK. Khi chạy chương trình bạn nhận được kết quả.
you’re getting: a computer and a monitor and a disk and a disk
Không tồi. Bạn đã mở rộng một đối tượng gốc thật đơn giản bằng cách bao bọc nó trong nhiều lớp trang trí decorator khác nhau, tránh việc phải chỉnh sửa trong mã nguồn gốc. Và đó là Mẫu Thiết Kế Trang Trí Decorator.
Download full source code use abstract class – CSharp
Download full source code use interface – CSharp
Ref:
https://haihth.wordpress.com/2013/02/21/dp-chapter3/
https://sourcemaking.com/design_patterns/decorator