I. Giới thiệu:
Decorator Pattern là một Design Pattern thuộc nhóm Structural. Nó cho phép chúng ta thêm các behavior mới cho một object (wrapped object) bằng cách đặt object đó vào trong một object khác (wrapper object) chứa đựng behaviour cần được thêm vào.
- Component Interface: định nghĩa các thuộc tính và phương thức cho wrapper và wrapped object.
- Concrete Component: là wrapped object cơ bản, nó cho phép các Decorator có thể wrap nó bên trong để thêm các behavior mới. Concrete Component sẽ được implement Component Interface.
- Base Decorator: là class cha của các Concrete Decortor, nó cũng được implement Component Interface. Bên trong Decorator sẽ chứa object của một wrapped object và cũng sẽ có những phương thức giống với wrapped object đó.
- Concrete Decorator: class kế thừa Base Decorator, là nơi định nghĩa các behavior mới cần được thêm vào wrapped object.
II. Cách thức hoạt động:
Decorator Pattern hoạt động theo cơ chế tạo ra nhiều object là các Concreate Decorator để bao bọc lẫn nhau. Mỗi khi cần thêm một behavior mới cho object thì Decorator Pattern sẽ tạo ra một Concreate Decorator để xử lý behavior và Concrete Decorator này sẽ là object mới (wrapper object) bao bọc object cũ (wrapped object).
III. Decorator Pattern được sử dụng khi nào?
Decorator Pattern được sử dụng khi muốn thêm behavior vào một object mà không muốn thay đổi cấu trúc của object đó.
IV. Ví dụ:
Component protocol
1 2 3 4 5 | <span class="token keyword">protocol</span> <span class="token builtin">Component</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">String</span> <span class="token punctuation">}</span> |
Concrete Component
1 2 3 4 5 6 7 | <span class="token keyword">class</span> <span class="token class-name">ConcreteComponent</span><span class="token punctuation">:</span> <span class="token builtin">Component</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">String</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">"ConcreteComponent"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Base Decorator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">class</span> <span class="token class-name">Decorator</span><span class="token punctuation">:</span> <span class="token builtin">Component</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">var</span> component<span class="token punctuation">:</span> <span class="token builtin">Component</span> <span class="token keyword">init</span><span class="token punctuation">(</span><span class="token number">_</span> component<span class="token punctuation">:</span> <span class="token builtin">Component</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>component <span class="token operator">=</span> component <span class="token punctuation">}</span> <span class="token comment">/// The Decorator delegates all work to the wrapped component.</span> <span class="token keyword">func</span> <span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">String</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> component<span class="token punctuation">.</span><span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Concrete Decorator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">class</span> <span class="token class-name">ConcreteDecoratorA</span><span class="token punctuation">:</span> <span class="token builtin">Decorator</span> <span class="token punctuation">{</span> <span class="token comment">/// Decorators may call parent implementation of the operation, instead of</span> <span class="token comment">/// calling the wrapped object directly. This approach simplifies extension</span> <span class="token comment">/// of decorator classes.</span> <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">String</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">"ConcreteDecoratorA("</span> <span class="token operator">+</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">")"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">ConcreteDecoratorB</span><span class="token punctuation">:</span> <span class="token builtin">Decorator</span> <span class="token punctuation">{</span> <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">String</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">"ConcreteDecoratorB("</span> <span class="token operator">+</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">")"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Sử dụng
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">class</span> <span class="token class-name">Client</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">someClientCode</span><span class="token punctuation">(</span>component<span class="token punctuation">:</span> <span class="token builtin">Component</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"Result: "</span> <span class="token operator">+</span> component<span class="token punctuation">.</span><span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"Client: I've got a simple component"</span><span class="token punctuation">)</span> <span class="token keyword">let</span> simple <span class="token operator">=</span> <span class="token function">ConcreteComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">Client</span><span class="token punctuation">.</span><span class="token function">someClientCode</span><span class="token punctuation">(</span>component<span class="token punctuation">:</span> simple<span class="token punctuation">)</span> <span class="token keyword">let</span> decorator1 <span class="token operator">=</span> <span class="token function">ConcreteDecoratorA</span><span class="token punctuation">(</span>simple<span class="token punctuation">)</span> <span class="token keyword">let</span> decorator2 <span class="token operator">=</span> <span class="token function">ConcreteDecoratorB</span><span class="token punctuation">(</span>decorator1<span class="token punctuation">)</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"nClient: Now I've got a decorated component"</span><span class="token punctuation">)</span> <span class="token builtin">Client</span><span class="token punctuation">.</span><span class="token function">someClientCode</span><span class="token punctuation">(</span>component<span class="token punctuation">:</span> decorator2<span class="token punctuation">)</span> |
V. Tài liệu tham khảo:
- Decorator Pattern by refactoring.guru