Intent (khái quát)
Facade là một structural design pattern
cung cấp giao diện đơn giản cho thư viện, framework hoặc bất kỳ tập hợp phức tạp nào khác của các class.
Problem (vấn đề)
Hãy tưởng tượng rằng bạn phải làm cho mã của mình hoạt động với một tập hợp các đối tượng thuộc về một thư viện hay framework. Thông thường, bạn cần phải khởi tạo tất cả các đối tượng đó, theo dõi các phụ thuộc, thực thi các phương thức theo đúng thứ tự, v.v.
Do đó, logic nghiệp vụ trong các class của bạn sẽ trở nên gắn kết chặt chẽ với các chi tiết triển khai của các class bên thứ 3, khiến cho việc hiểu và duy trì rất khó khăn.
Solution (giải pháp)
facade là một lớp cung cấp giao diện đơn giản cho một hệ thống con phức tạp chứa nhiều phần chuyển động. Một facade có thể cung cấp chức năng hạn chế so với làm việc trực tiếp với hệ thống con. Tuy nhiên, nó chỉ bao gồm những tính năng mà khách hàng thực sự quan tâm.
facade rất tiện dụng khi bạn cần tích hợp ứng dụng của mình với một thư viện tinh vi có hàng tá tính năng, nhưng bạn chỉ cần một chút chức năng của nó.
Ví dụ như bạn có một ứng dụng giúp tải các video ngắn vui nhộn với mèo lên phương tiện truyền thông xã hội, sử dụng thư viện chuyển đổi video chuyên nghiệp. Tuy nhiên, tất cả những gì thực sự cần chỉ là một phương thức duy nhất encode(filename, format)
. Sau khi tạo một lớp với một phương thức như vậy và kết nối nó với thư viện chuyển đổi video, bạn sẽ có facade đầu tiên.
Real-World Analogy (liên hệ với thực tế)
Khi bạn gọi một cửa hàng để đặt hàng bằng điện thoại, Một tổng đài viên là facade của bạn cho tất cả các dịch vụ của các phòng ban trong cửa hàng. Tổng đài viên cung cấp cho bạn một giao diện thoại đơn giản cho hệ thống đặt hàng, cổng thanh toán và các dịch vụ giao hàng khác nhau.
Structure (cách tổ chức)
- Facadecung cấp quyền truy cập thuận tiện vào một phần cụ thể của chức năng hệ thống con. Nó biết nơi thưc hiện yêu cầu của client và cách mà tất cả các bộ phận vận hành.
- Additional Facade có thể được tạo để ngăn ô nhiễm một facade, các tính năng không liên quan có thể làm cho nó trở thành một cấu trúc phức tạp khác. Additional Facade có thể được sử dụng bởi cả Client và các facade khác.
- Complex Subsystem bao gồm hàng tá đối tượng khác nhau. Để làm cho tất cả chúng làm điều gì đó có ý nghĩa, bạn phải đi sâu vào chi tiết triển khai hệ thống con, như khởi tạo các đối tượng theo đúng thứ tự và cung cấp cho chúng dữ liệu theo định dạng thích hợp.
Các class của hệ thống con không hề biết về sự tồn tại của Facade. Chúng hoạt động trong hệ thống và làm việc trực tiếp với nhau. - Client sử dụng Facade thay vì gọi trực tiếp các đối tượng hệ thống con.
Applicability (sử dụng khi)
- Sử dụng mẫu Facade khi bạn cần có giao diện giới hạn nhưng đơn giản với hệ thống con phức tạp.
- Sử dụng Facade khi bạn muốn cấu trúc một hệ thống con thành các layers.
How to Implement (cách cài đặt)
- Kiểm tra xem có thể cung cấp giao diện đơn giản hơn so với những gì hệ thống con hiện có đã cung cấp hay không. Bạn có thể đi đúng hướng nếu giao diện này làm cho client code độc lập với nhiều lớp của hệ thống con.
- Khai báo và triển khai giao diện này trong lớp facade mới. Facade sẽ chuyển hướng các lời gọi từ client code đến các đối tượng thích hợp của hệ thống con. Facade phải chịu trách nhiệm khởi tạo hệ thống con và quản lý vòng đời tiếp theo của nó trừ khi client code đã thực hiện việc này.
- Để nhận được toàn bộ lợi ích từ pattern, làm cho tất cả client code chỉ giao tiếp với hệ thống con thông qua facade. Bây giờ mã máy khách được tách biệt khỏi mọi thay đổi trong mã hệ thống con. Ví dụ, khi một hệ thống con được nâng cấp lên phiên bản mới, bạn sẽ chỉ cần sửa đổi mã ở facade.
- Nếu facade trở nên quá lớn, hãy xem xét trích xuất một phần hành vi của nó sang một lớp facade mới, hãy tinh tế.
Decorator in Ruby (ví dụ với ngôn ngữ ruby)
main.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | <span class="token comment"># Lớp Facade cung cấp một giao diện đơn giản cho logic phức tạp </span> <span class="token comment"># của một hoặc một số hệ thống con.</span> <span class="token comment"># Facade ủy thác các yêu cầu của client cho các đối tượng</span> <span class="token comment"># thích hợp trong hệ thống con.</span> <span class="token comment"># Facade cũng chịu trách nhiệm quản lý vòng đời của họ.</span> <span class="token comment"># Tất cả điều này bảo vệ client khỏi sự phức tạp </span> <span class="token comment"># không mong muốn của hệ thống con.</span> <span class="token keyword">class</span> <span class="token class-name">Facade</span> <span class="token comment"># Tùy thuộc vào nhu cầu của ứng dụng của bạn,</span> <span class="token comment"># bạn có thể cung cấp cho Facade các đối tượng hệ thống con hiện có</span> <span class="token comment"># hoặc buộc Facade phải tự tạo chúng.</span> <span class="token keyword">def</span> <span class="token function">initialize</span><span class="token punctuation">(</span>subsystem1<span class="token punctuation">,</span> subsystem2<span class="token punctuation">)</span> <span class="token variable">@subsystem1</span> <span class="token operator">=</span> subsystem1 <span class="token operator">||</span> <span class="token constant">Subsystem1</span><span class="token punctuation">.</span><span class="token keyword">new</span> <span class="token variable">@subsystem2</span> <span class="token operator">=</span> subsystem2 <span class="token operator">||</span> <span class="token constant">Subsystem2</span><span class="token punctuation">.</span><span class="token keyword">new</span> <span class="token class-name">end</span> <span class="token comment"># Các phương thức của Facade là các shortcut thuận tiện cho chức năng tinh vi</span> <span class="token comment"># của các hệ thống con.</span> <span class="token comment"># Tuy nhiên, client chỉ nhận được một phần khả năng của hệ thống con.</span> <span class="token keyword">def</span> operation results <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> results<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'Facade initializes subsystems:'</span><span class="token punctuation">)</span> results<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token variable">@subsystem1</span><span class="token punctuation">.</span>operation1<span class="token punctuation">)</span> results<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token variable">@subsystem2</span><span class="token punctuation">.</span>operation1<span class="token punctuation">)</span> results<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'Facade orders subsystems to perform the action:'</span><span class="token punctuation">)</span> results<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token variable">@subsystem1</span><span class="token punctuation">.</span>operation_n<span class="token punctuation">)</span> results<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token variable">@subsystem2</span><span class="token punctuation">.</span>operation_z<span class="token punctuation">)</span> results<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">)</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token comment"># Hệ thống con có thể chấp nhận các yêu cầu từ facade hoặc client trực tiếp.</span> <span class="token comment"># Trong mọi trường hợp, đối với Hệ thống con, Facade vẫn là một ứng dụng client khác </span> <span class="token comment"># và nó không phải là một phần của Hệ thống con.</span> <span class="token keyword">class</span> <span class="token class-name">Subsystem1</span> <span class="token comment"># @return [String]</span> <span class="token keyword">def</span> operation1 <span class="token string">'Subsystem1: Ready!'</span> <span class="token keyword">end</span> <span class="token comment"># ...</span> <span class="token comment"># @return [String]</span> <span class="token keyword">def</span> operation_n <span class="token string">'Subsystem1: Go!'</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token comment"># Một số facade có thể làm việc với nhiều hệ thống con cùng một lúc.</span> <span class="token keyword">class</span> <span class="token class-name">Subsystem2</span> <span class="token comment"># @return [String]</span> <span class="token keyword">def</span> operation1 <span class="token string">'Subsystem2: Get ready!'</span> <span class="token keyword">end</span> <span class="token comment"># ...</span> <span class="token comment"># @return [String]</span> <span class="token keyword">def</span> operation_z <span class="token string">'Subsystem2: Fire!'</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token comment"># Client code hoạt động với các hệ thống con phức tạp thông qua giao diện đơn giản</span> <span class="token comment"># do Facade cung cấp.</span> <span class="token comment"># Khi một facade quản lý vòng đời của hệ thống con, client thậm chí</span> <span class="token comment"># có thể không biết về sự tồn tại của hệ thống con.</span> <span class="token comment"># Cách tiếp cận này cho phép bạn giữ sự phức tạp trong tầm kiểm soát.</span> <span class="token keyword">def</span> <span class="token function">client_code</span><span class="token punctuation">(</span>facade<span class="token punctuation">)</span> print facade<span class="token punctuation">.</span>operation <span class="token keyword">end</span> <span class="token comment"># Mã máy khách có thể có một số đối tượng của hệ thống con đã được tạo.</span> <span class="token comment"># Trong trường hợp này, có thể đáng để khởi tạo Facade</span> <span class="token comment"># với các đối tượng này thay vì để Facade tạo phiên bản mới.</span> subsystem1 <span class="token operator">=</span> <span class="token constant">Subsystem1</span><span class="token punctuation">.</span><span class="token keyword">new</span> <span class="token class-name">subsystem2</span> <span class="token operator">=</span> <span class="token constant">Subsystem2</span><span class="token punctuation">.</span><span class="token keyword">new</span> <span class="token class-name">facade</span> <span class="token operator">=</span> <span class="token constant">Facade</span><span class="token punctuation">.</span><span class="token keyword">new</span><span class="token punctuation">(</span>subsystem1<span class="token punctuation">,</span> subsystem2<span class="token punctuation">)</span> <span class="token function">client_code</span><span class="token punctuation">(</span>facade<span class="token punctuation">)</span> |
output.txt:
1 2 3 4 5 6 7 | Facade initializes subsystems: Subsystem1: Ready! Subsystem2: Get ready! Facade orders subsystems to perform the action: Subsystem1: Go! Subsystem2: Fire! |