1. 外觀模式
1.1 概述
外觀模式比較簡單,是應用比較廣泛的一種設計模式。
舉個栗子說明一下,比如說,現在我在家炒菜,我需要準備菜、調料、油等,然後再下鍋炒,最後完成。但是,如果我們去飯店喫,只需要跟服務員說一下菜名,服務員就會爲我們提供一份美味佳餚。本來如此繁複的一個工作,現在有了服務員的加入而變得簡單,我們不需要和菜、調料等直接接觸,也不需要了解具體的細節,就得到了我們想要的結果,這就應用到了今天要說到的模式——外觀模式。
1.2 定義
外觀模式,爲子系統中的一組接口提供一個一致的界面,此模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。(引自《大話設計模式》)
1.3 結構圖
這裏主要涉及三個角色:
- 外觀角色(Facade):外觀模式的核心。對外爲客戶提供一組可用的接口,對內熟悉每一個子系統的功能,並根據客戶需求對子系統的功能進行組合。
- 子系統角色(SubSystem):一個應用中可存在一個或多個子系統類,實現子系統功能,被外觀角色所調用,處理Facade指派的功能。值得注意的是,子系統類中沒有Facade的任何信息,即沒有對Facade對象的引用。
- 客戶角色(Client):通過調用Facade完成需要實現的功能。
2. 實戰應用
2.1 實例說明
簡單舉個例子說明。現在有一個網站要做登錄模塊,登錄的信息有用戶名、密碼和圖片驗證碼,忽略前臺需要做的一些相關規則的正則校驗,只考慮後端服務端的校驗。那麼,有如下步驟:
(1)圖片驗證碼校驗。
(2)用戶是否存在。
(3)密碼校驗。
由於這三個步驟的功能是相互獨立的,而且也有可能被其他模塊所調用,也考慮到讓設計符合單一職責,所以可以將這三部分寫到三個類中。
2.2 類圖
2.3 實現代碼
子系統一
package main.mode.wgms;
public class PictureCode {
public void CheckPictureCode() {
System.out.println("校驗圖片驗證碼");
}
}
子系統二
package main.mode.wgms;
public class UserInfo {
public void checkUserName() {
System.out.println("校驗用戶名是否存在");
}
}
子系統三
package main.mode.wgms;
public class PwdInfo {
public void checkPwd() {
System.out.println("校驗用戶名密碼是否匹配");
}
}
外觀類
package main.mode.wgms;
public class LoginFacade {
private PictureCode code;
private UserInfo user;
private PwdInfo pwd;
public LoginFacade() {
code = new PictureCode();
user = new UserInfo();
pwd = new PwdInfo();
}
public void login(){
System.out.println("進入登錄功能......");
code.CheckPictureCode();
user.checkUserName();
pwd.checkPwd();
System.out.println("登錄成功......");
}
}
客戶端類中調用Facade類
package main.mode.wgms;
public class Client {
public static void main(String[] args) {
LoginFacade login = new LoginFacade();
login.login();
}
}
結果
2.4 分析
(1)子系統之間相互獨立,完成各自的功能。
(2)外觀類按客戶需求組合子系統的功能,完成客戶所需功能。
(3)從客戶端代碼可以看出,客戶不需要知道登錄具體做了哪些操作,即不知道PictureCode、UserInfo、PwdInfo的存在,只需要調用LoginFacade完成登錄功能即可。客戶端不需要知道系統內部的組成,不需要了解內部實現的細節,使得客戶端和子系統類之間解耦。
3. 總結
3.1 優點
- 外觀模式簡單易用,完美地體現了依賴倒轉原則和迪米特法則的思想。
- 使客戶端和子系統之間解耦,提高了子系統的易擴展性和複用性。
- 客戶端代碼很簡單。
3.2 缺點
- 外觀類違背了開放-封閉原則,增加新的子系統需要修改外觀類的代碼。
3.3 應用場景
- 在分層架構中,可以通過外觀類建立層與層之間的聯繫,減少層之間的聯繫,降低耦合性。
- 客戶端與子系統聯繫過多時,或者子系統需要不斷的重構或修改時,可以增加外觀類,將客戶端與子系統解耦,增加子系統的可擴展性和複用性。
- 當需要訪問一個複雜或難以維護和擴展的遺留系統時,可以引入外觀類,讓外觀類與遺留代碼做交互。