外觀模式(門面模式)
定義:它爲子系統中的一組接口提供一個統一的高層接口。這一接口使得子系統更加容易使用
類型:結構型
適用場景:
- 子系統越來越複雜,增加外觀模式提供簡單的接口調用
- 構建多層系統接口,利用外觀對象作爲每層的入口,簡化層間調用
優點:
- 簡化了調用過程,無需深入瞭解子系統,防止帶來的風險
- 減少系統依賴,鬆散耦合
- 更好的劃分訪問層次
- 符合迪米特法則(最少知道原則)
缺點:
- 增加子系統,擴展子系統行爲容易引入風險
- 不符合開閉原則
UML類圖:
Facade:門面角色,客戶端可以調用這個角色的方法。此角色知曉子系統的所有功能和責任。一般情況下,本橘色會將所有從客戶端發來的請求委託到相應的子系統,也就是說該角色並沒有實際的業務邏輯,而是一個委託類
Subsystem:子系統角色,可以同時有一個或者多個子系統。每一個子系統都不是單獨的類,而是一個類的集合。子系統並不知道門面的存在。對於子系統而言,門面僅僅是另外一個客戶端而已
示例
ModuleA,ModuleB,ModuleC均是獨立的功能模塊,現在把他們都看作是子系統的內部結構組成,提供個Facade門面供客戶端調用
- 模塊A、模塊B、模塊C
public class ModuleA {
//示意方法
public void testA() {
System.out.println("調用ModuleA中的testA方法");
}
}
public class ModuleB {
//示意方法
public void testB() {
System.out.println("調用ModuleB中的testB方法");
}
}
public class ModuleC {
//示意方法
public void testC() {
System.out.println("調用ModuleC中的testC方法");
}
}
- Facade門面(對子系統的各個功能模塊進行封裝、子系統的功能模塊之間的調用邏輯也可以在這裏完成)
public class Facade {
//示意方法,滿足客戶端需要的功能
public void test(){
ModuleA a = new ModuleA();
a.testA();
ModuleB b = new ModuleB();
b.testB();
ModuleC c = new ModuleC();
c.testC();
}
}
- 客戶端
public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.test();
}
}
Facade類其實相當於A、B、C模塊的外觀界面,有了這個Facade類,那麼客戶端就不需要親自調用子系統中的A、B、C模塊了,也不需要知道系統內部的實現細節,甚至都不需要知道A、B、C模塊的存在,客戶端只需要跟Facade類交互就好了,從而更好地實現了客戶端和子系統中A、B、C模塊的解耦,讓客戶端更容易地使用系統。
- 在日常J2EE開發中,我們最常與controller/service/dao打交道,這就是典型的外觀模式的實現,這裏以一個訂單業務舉例
圖中的Dao層的OrderDao、OrderLogDao可以看做是子系統的組成部分,主要圍繞的是數據庫的增刪改查,而Service層中的OrderServiceImpl就是我們外觀對象實現,通常我們會根據具體的業務邏輯去調用dao層提供的api,這裏就提供了一個createOrder
創建訂單的外觀方法給Contorller層(客戶端)進行調用,客戶端根本不需要了解具體訂單生成邏輯就可以完成訂單的創建。這裏對外觀類進行了接口抽象,客戶端依賴的是OrderService接口而不是OrderServiceImpl實現類,這樣就解除了客戶端與子系統的依賴,而讓客戶端只依賴於外觀接口,這是一個優秀的解耦實踐。
相關的設計模式
- 外觀模式和中介者模式
外觀模式關注的是外界和子系統之間的交互,而中介者模式關注的是子系統之間的內部交互
- 外觀模式和單例模式
通常可以把外觀模式中的外觀對象做成是單例模式
- 外觀模式和抽象工廠模式
外觀類可以通過抽象工廠獲取子系統的實例,這樣子系統可以對外觀類進行屏蔽
- 外觀模式和代理模式
代理對象代表一個單一對象而外觀對象代表一個子系統,代理的客戶對象無法直接訪問對象,由代理提供單獨的目標對象的訪問,而通常外觀對象提供對子系統各元件功能的簡化的共同層次的調用接口。代理是一種原來對象的代表,其他需要與這個對象打交道的操作都是和這個代表交涉的
- 外觀模式和適配器模式
外觀與適配器都是對現存系統的封裝。外觀定義的新的接口,而適配器則是複用一個原有的接口,適配器是使兩個已有的接口協同工作,而外觀則是爲現存系統提供一個更爲方便的訪問接口。如果硬要說外觀是適配,那麼適配器有用來適配對象的,而外觀是用來適配整個子系統的。也就是說,外觀所針對的對象的粒度更大
使用典範
- SLF4J日誌框架
- tomcat中的RequestFacade
- java.lang.Class