1. 概述
例子1:一個電源總開關可以控制四盞燈、一個風扇、一台空調和一台電視機的啟動和關閉。該電源總開關可以同時控制上述所有電器裝置,電源總開關即為該系統的外觀模式設計。
2. 問題
為了降低複雜性,常常将系統劃分為若幹個子系統。但是如何做到各個系統之間的通信和互相依賴關系達到最小呢?
3. 解決方案
facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。引入外觀角色之後,使用者隻需要直接與外觀角色互動,使用者與子系統之間的複雜關系由外觀角色來實作,進而降低了系統的耦合度。
4. 适用性
1) 當你要為一個複雜子系統提供一個簡單接口時。子系統往往因為不斷演化而變得越來越複雜。大多數模式使用時都會産生更多更小的類。
這使得子系統更具可重用性,也更容易對子系統進行定制,但這也給那些不需要定制子系統的使用者帶來一些使用上的困難。facade可以提供一個簡單的預設視圖,
這一視圖對大多數使用者來說已經足夠,而那些需要更多的可定制性的使用者可以越過facade層。
2) 客戶程式與抽象類的實作部分之間存在着很大的依賴性。引入 facade将這個子系統與客戶以及其他的子系統分離,可以提高子系統的獨立性 和可移植性。
3) 當你需要建構一個層次結構的子系統時,使用 facade模式定義子系統中每層的入口點。如果子系統之間是互相依賴的,你可以讓它們僅通過facade進行通訊,進而簡化了它們之間的依賴關系。
5.
結構
6.構模組化式的組成
7.
效果
facade模式有下面一些優點: 1)對客戶屏蔽子系統元件,減少了客戶處理的對象數目并使得子系統使用起來更加容易。通過引入外觀模式,客戶代碼将變得很簡單,與之關聯的對象也很少。 2)實作了子系統與客戶之間的松耦合關系,這使得子系統的元件變化不會影響到調用它的客戶類,隻需要調整外觀類即可。 3)降低了大型軟體系統中的編譯依賴性,并簡化了系統在不同平台之間的移植過程,因為編譯一個子系統一般不需要編譯所有其他的子系統。一個子系統的修改對其他子系統沒有任何影響,而且子系統内部變化也不會影響到外觀對象。 4)隻是提供了一個通路子系統的統一入口,并不影響使用者直接使用子系統類。 facade模式的缺點 1) 不能很好地限制客戶使用子系統類,如果對客戶通路子系統類做太多的限制則減少了可變性和靈活性。 2) 在不引入抽象外觀類的情況下,增加新的子系統可能需要修改外觀類或用戶端的源代碼,違背了“開閉原則”。
8.
實作
我們使用開關的例子; <?php /** * 外觀模式 * */ class switchfacade { private $_light = null; //電燈 private $_ac = null; //空調 private $_fan = null; //電扇 private $_tv = null; //電視 public function __construct() { $this->_light = new light(); $this->_fan = new fan(); $this->_ac = new airconditioner(); $this->_tv = new television(); } /** * 晚上開電燈 * */ public function method1($isopen =1) { if ($isopen == 1) { $this->_light->on(); $this->_fan->on(); $this->_ac->on(); $this->_tv->on(); }else{ $this->_light->off(); $this->_fan->off(); $this->_ac->off(); $this->_tv->off(); } * 白天不需要電燈 public function method2() { } /******************************************子系統類 ************/ * */ class light { private $_isopen = 0; public function on() { echo 'light is open', '<br/>'; $this->_isopen = 1; public function off() { echo 'light is off', '<br/>'; $this->_isopen = 0; class fan echo 'fan is open', '<br/>'; echo 'fan is off', '<br/>'; class airconditioner echo 'airconditioner is open', '<br/>'; echo 'airconditioner is off', '<br/>'; class television echo 'television is open', '<br/>'; echo 'television is off', '<br/>'; * 客戶類 class client { static function open() { $f = new switchfacade(); $f->method1(1); static function close() { $f->method1(0); client::open();
11.
與其他相關模式
mediator的同僚對象知道中介者并與它通信,而不是直接與其他同類對象通信。相對而言,facade模式僅對子系統對象的接口進行抽象,進而使它們更容易使用;它并不定義新功能,子系統也不知道facade的存在。 通常來講,僅需要一個facade對象,是以facade對象通常屬于singleton模式。 擴充卡模式是将一個接口通過适配來間接轉換為另一個接口。 外觀模式的話,其主要是提供一個整潔的一緻的接口給用戶端。
12. 總結
5)不要試圖通過外觀類為子系統增加新行為 ,不要通過繼承一個外觀類在子系統中加入新的行為,這種做法是錯誤的。外觀模式的用意是為子系統提供一個集中化和簡化的溝通管道,而不是向子系統加入新的行為,新的行為的增加應該通過修改原有子系統類或增加新的子系統類來實作,不能通過外觀類來實作。
13.模式擴充
一個系統有多個外觀類: 在外觀模式中,通常隻需要一個外觀類,并且此外觀類隻有一個執行個體,換言之它是一個單例類。在很多情況下為了節約系統資源,一般将外觀類設計為單例類。當然這并不意味着在整個系統裡隻能有一個外觀類,在一個系統中可以設計多個外觀類,每個外觀類都負責和一些特定的子系統互動,向使用者提供相應的業務功能。 不要試圖通過外觀類為子系統增加新行為: 不要通過繼承一個外觀類在子系統中加入新的行為,這種做法是錯誤的。外觀模式的用意是為子系統提供一個集中化和簡化的溝通管道,而不是向子系統加入新的行為,新的行為的增加應該通過修改原有子系統類或增加新的子系統類來實作,不能通過外觀類來實作。 <a target="_blank" href="http://blog.csdn.net/hguisu/article/details/7571617">外觀模式與迪米特法則:</a> 外觀模式創造出一個外觀對象,将用戶端所涉及的屬于一個子系統的協作夥伴的數量減到最少,使得用戶端與子系統内部的對象的互相作用被外觀對象所取代。外觀類充當了客戶類與子系統類之間的“第三者”,降低了客戶類與子系統類之間的耦合度,外觀模式就是實作代碼重構以便達到“迪米特法則”要求的一個強有力的武器。 抽象外觀類的引入: 當增加新的子系統或者移除子系統時需要修改外觀類,可以通過引入抽象外觀類在一定程度上解決該問題,用戶端針對抽象外觀類進行程式設計。對于新的業務需求,不修改原有外觀類,而對應增加一個新的具體外觀類,由新的具體外觀類來關聯新的子系統對象,同時通過修改配置檔案來達到不修改源代碼并更換外觀類的目的。 uml: