Background
Break News
How to add local font to Tailwind Css and NextJS? - Tutorial Design Pattern? - Blockchain Technology, How to create own Bitcoin virtual currency - Zustand mordern management state - Design Pattern - Flyweight Pattern? - Docker Full training Topic

[Tutorial] Design Pattern - Decorator Pattern

Sunday 24 July 2016
|
Read: Completed in minutes

[Tutorial] Design Pattern - Decorator Pattern

"Add responsibilities to objects dynamical"


The Decorator attaches additional responsibilities to an object dynamically. The ornaments that are added to pine or fir trees are examples of Decorators. Lights, garland, candy canes, glass ornaments, etc., can be added to a tree to give it a festive look. The ornaments do not change the tree itself which is recognizable as a Christmas tree regardless of particular ornaments used. As an example of additional functionality, the addition of lights allows one to "light up" a Christmas tree. 

Another example: assault gun is a deadly weapon on it's own. But you can apply certain "decorations" to make it more accurate, silent and devastating.

Design Pattern - Decorator Pattern




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”







Bạn đang làm nhân viên tư vấn Thiết Kế Mẫu tại công ty GigantoComputer, với mức lương khá cao và bạn đang ở trong căn tin công ty.

“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”  

Một trong những khía cạnh quan trọng nhất trong quá trình phát triển một ứng dụng là các nhà phát triển và lập trình viên phải đối đầu với sự thay đổi, và đó là lý do vì sao các mẫu thiết kế này lại được giới thiệu trước tiên. Có thể nói các Mẫu Thiết Kế sẽ giúp bạn giải quyết được các sự thay đổi, và bạn có thể dễ dàng chuyển đổi mã nguồn của mình cho các trường hợp mới và bất khả kháng. Như tôi đã nói qua trong suốt cuốn sách này,lập trình viên thường tiêu tốn thời gian cho việc mở rộng và thay đổi mã nguồn hơn là phát triển mã nguồn gốc.

Mẫu chiến lược Strategy đã được giới thiệu trước đây trong chương II, giúp bạn xử lý những sự thay đổi bằng cách cho phép bạn chọn lựa một thuật toán thích hợp từ một tập hợp thuật toán bên ngoài hơn là phải viết lại mã nguồn. Mẫu trang trí Decorator cũng tương tự vậy, nó cho phép bạn viết tiếp mã nguồn, tránh việc sửa đổi lên mã nguồn gốc, trong khi vẫn đáp ứng được yêu cầu thay đổi. Đó là điểm chính yếu tôi muốn nhấn mạnh.

Ghi nhớ: Hãy làm cho mã nguồn của bạn đáp ứng được nguyên tắc “Luôn đóng cho sự chỉnh sửa, và luôn mở cho việc mở rộng” càng nhiều càng tốt. Nói cách khác, hãy thiết kế mã nguồn sao cho không cần phải thay đổi gì nhiều nhưng luôn có thể mở rộng khi cần.

Đây là một ví dụ cho việc viết mã nguồn luôn đóng cho sự thay đổi.
Công ty mà bạn đang làm tư vấn, công ty GigantoComputer, quyết định làm một cái máy vi tính mới. Đây là mã nguồn của lớp Computer:

 
public class cComputer  
    {
            public cComputer() { }
            public string description()
            {
                return "You're getting a computer";
            }
    }
    



Khi một đối tượng computer được khởi tạo. Phương thức description sẽ trả về văn bản “You’re getting a computer.” . Tới giờ mọi việc vẫn tốt đẹp. Nhưng một số khách hàng quyết định rằng họ muốn có một cái đĩa cứng trong máy tính. “Không vấn đề gì cả” Các lập viên trong công ty đáp. “ Chúng ta chỉ cần chỉnh sửa mã nguồn lại một chút như sau:”


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";

Bạn có thể thấy vấn đề ở đây: Các lập trình viên phải thay đổi mã nguồn mỗi khi khách hàng thay đổi yêu cầu của họ. Rõ ràng, đó là vấn đề chính.
Và bạn, với cương vị là tư vấn mẫu thiết kế, sẽ chỉnh sửa nó.
 
Tôi phải nhắc lại một lần nữa: càng nhiều càng tốt, hãy viết mã nguồn của bạn đóng cho việc sửa đổi, nhưng mở cho việc mở rộng. Trong chương II, bạn đã biết cách làm việc với mẫu chiến lược Strategy. Đó là, bạn đóng gói mã nguồn vào các thuật toán riêng biệt để sử dụng dễ dàng, hơn là việc xử lý chúng thông qua các lớp con.
Mẫu trang trí Decorator có một cách tiếp cận khác. Thay vì sử dụng một thuật toán bên ngoài, mẫu thiết kế này sử dụng một phương pháp “bao bọc” mã nguồn của bạn để mở rộng chúng.
Ghi nhớ: Định nghĩa chính thức của mẫu trang trí Decorator trong sách của GoF có viết: “Gắn kết thêm một số tính năng cho đối tượng một cách linh động. Mẫu trang trí Decorator cung cấp một phương pháp linh hoạt hơn là sử dụng lớp con để mở rộng chức năng cho đối tượng”
Mẫu thiết kế này được gọi là “Người trang trí” Decorator nhưng dường như đó là tên gọi rườm rà. Một cái tên tốt hơn cho mẫu này có thể là “Người tăng thêm” Augmentor hay “Người mở rộng” Extender bởi vì nó cho phép bạn: tăng thêm hay mở rộng một lớp một cách linh động khi chương trình được thực thi. Tuy nhiên, như bạn thấy trong chương này, thuật ngữ “Người trang trí” Decorator còn giúp bạn hiểu rõ hơn khái niệm “đóng cho việc chỉnh sửa, mở cho việc mở rộng”. Khi bạn làm hành động bao bọc mã nguồn để mở rộng thêm chức năng, bạn không cần thiết chỉnh sửa lại mã nguồn cũ, bạn chủ yếu tập trung vào việc trang trí nó.






Và đây là cách mà nó làm việc. Bạn bắt đầu với một cái máy tính computer đơn giản sau:

Design Pattern - Decorator Pattern



Khi bạn gọi phương thức description, bạn nhận được kết quả “You’re getting a computer”. Bây giờ bạn muốn thêm ít phần cứng, một ổ cứng mới chẳng hạn. Trong trường hợp này, bạn có thể thêm một lớp bao bọc wrapper như sau:


Design Pattern - Decorator Pattern


Bây giờ khi bạn gọi phương thức description của lớp bao bọc wrapper, nó sẽ gọi phương thức description của đối tượng computer để nhận được kết quả “You’re getting a computer “ và đối tượng ổ cứng disk sẽ trả về kết quả “and a disk”.  Kết quả bạn nhận được “You’re getting a computer and a disk”
Nếu bạn muốn thêm vài thứ nữa vào lớp máy tính Computer, bạn hãy đặt nó vào lớp bao bọc wrapper, ví dụ như thêm vào cái màn hình Monitor:


Design Pattern - Decorator Pattern

Bây giờ khi bạn gọi phương thức description, mọi việc sẽ xảy ra như sau:
–      Đối tượng computer, sẽ thực hiện phương thức description để tạo ra kết quả “You’re getting a computer”
–      Đối tượng disk, sẽ thực hiện tiếp phương thức trên để thêm vào “and a disk”
–      Đối tượng monitor, tiếp tục thực hiện phương thức description để thêm vào “and a monitor”
–      Kết quả là bạn nhận được “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";
            }
    
    } 
    


OK. Bạn đã hoàn thành cái máy tính đơn giản. Bây giờ làm sao để tạo một lớp trang trí? Những lớp này hoạt động như là một lớp bao bọc cho lớp Computer, điều này có nghĩa là phải có một biến để lưu trữ một đối tượng computer. Một cách đơn giản để tạo lớp bao bọc wrapper là mở rộng lớp Computer.

Tạo dựng một Lớp trang trí Decorator



Bài này tôi dùng 2 cách, cách 1: là dùng abstract và cách 2 dùng interface trong CSharp, tôi có để lại source mẫu, bạn có thể xem và tham khảo :) Trong khi trình bày tôi dùng interface vì nó sẽ giúp các bạn dễ hiểu hơn

Download full source code use abstract class - CSharp

Download full source code use interface - CSharp

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

🙇🏼🙇🏼 We Appreciate Your Comments and Suggestions - Webzone, all things Tech Tips web development
Popular Webzone Tech Tips topic maybe you will be like it - by Webzone Tech Tips - Zidane
As a student, I found Blogspot very useful when I joined in 2014. I have been a developer for years . To give back and share what I learned, I started Webzone, a blog with tech tips. You can also search for tech tips zidane on Google and find my helpful posts. Love you all,

I am glad you visited my blog. I hope you find it useful for learning tech tips and webzone tricks. If you have any technical issues, feel free to browse my posts and see if they can help you solve them. You can also leave a comment or contact me if you need more assistance. Here is my blog address: https://learn-tech-tips.blogspot.com.

My blog where I share my passion for web development, webzone design, and tech tips. You will find tutorials on how to build websites from scratch, using hot trends frameworks like nestjs, nextjs, cakephp, devops, docker, and more. You will also learn how to fix common bugs on development, like a mini stackoverflow. Plus, you will discover how to easily learn programming languages such as PHP (CAKEPHP, LARAVEL), C#, C++, Web(HTML, CSS, javascript), and other useful things like Office (Excel, Photoshop). I hope you enjoy my blog and find it helpful for your projects. :)

Thanks and Best Regards!
Follow me on Tiktok @learntechtips and send me a direct message. I will be happy to chat with you.
Webzone - Zidane (huuvi168@gmail.com)
I'm developer, I like code, I like to learn new technology and want to be friend with people for learn each other
I'm a developer who loves coding, learning new technologies, and making friends with people who share the same passion. I have been a full stack developer since 2015, with more than years of experience in web development.
Copyright @2022(November) Version 1.0.0 - By Webzone, all things Tech Tips for Web Development Zidane
https://learn-tech-tips.blogspot.com