
原文地址:LoveDev
外觀模式(Facade Pattern):又稱為門面模式,為一組接口提供一個統一的入口。外觀模式是迪米特法則的一種具體實現,通過引入一個新的外觀角色降低原有系統的復雜度,同時降低客戶端類與子系統的耦合度。

外觀模式
- Facade(外觀角色):外觀角色中可以知道相關的多個子系統的功能和責任,客戶端調用它的方法,它再傳遞給相應的子系統對象處理
- SubSystem(子系統角色):子系統可以不是單獨的類,而是類的集合,它實現子系統的功能,每個子系統都可以被客戶端直接調用,或者被外觀角色調用,對于子系統而言,外觀角色也是一個客戶端。
最近習慣了自己做飯,雖然做飯的過程很痛苦,可是看到自己做出來的美食后,還是很幸福很有成就感的。就拿自己做飯吃和去餐館吃飯來舉例,把餐館看做外觀角色,讓它把買菜、切菜、炒菜、刷碗這些工作統一組織起來,我要做的就是告訴他要吃什么就行了,下面是示例代碼:
SubSystem 類:
// 買菜
public class BuyVegetable {
public void buy() {
LogUtils.i("買菜");
}
}
// 切菜
public class CutVegetable {
public void cut() {
LogUtils.i("切菜");
}
}
// 炒菜
public class CookVegetable {
public void cook() {
LogUtils.i("炒菜");
}
}
// 洗刷刷
public class WashDishes {
public void wash() {
LogUtils.i("洗刷刷");
}
}
Facade 類:
// 餐館
public class Restaurant {
private final BuyVegetable mBuyVegetable;
private final CutVegetable mCutVegetable;
private final CookVegetable mCookVegetable;
private final WashDishes mWashDishes;
public Restaurant() {
mBuyVegetable = new BuyVegetable();
mCutVegetable = new CutVegetable();
mCookVegetable = new CookVegetable();
mWashDishes = new WashDishes();
}
public void eat() {
mBuyVegetable.buy();
mCutVegetable.cut();
mCookVegetable.cook();
mWashDishes.wash();
}
}
Client 類:
// 自己做飯,需要跟這些子系統交互
BuyVegetable buyVegetable = new BuyVegetable();
CutVegetable cutVegetable = new CutVegetable();
CookVegetable cookVegetable = new CookVegetable();
WashDishes washDishes = new WashDishes();
buyVegetable.buy();
cutVegetable.cut();
cookVegetable.cook();
washDishes.wash();
// 去餐館吃飯,只需跟餐館交互
Restaurant restaurant = new Restaurant();
restaurant.eat();
有了外觀模式,需要交互的類就變成了一個,讓它負責和業務類實現交互,簡化負責的交互,降低系統的耦合度,但是在標準的外觀模式中,如果需要增刪改外觀類交互的子系統類,就需要改動客戶端源碼,這樣就違反了“開閉原則”,因此遇到此類情況需要引入抽象外觀類進行優化,還以上面例子為基礎:
AbstarctFacade 類:
public abstract class AbstractFacade {
public abstract void eat();
}
ConcreteFacade 類:
// 有些不用切就可以直接做的飯,比如面,這就需要把切菜移除掉
public class NoodlesRestaurant extends AbstractFacade{
private final BuyVegetable mBuyVegetable;
private final CookVegetable mCookVegetable;
private final WashDishes mWashDishes;
public NoodlesRestaurant() {
mBuyVegetable = new BuyVegetable();
mCookVegetable = new CookVegetable();
mWashDishes = new WashDishes();
}
@Override
public void eat() {
mBuyVegetable.buy();
mCookVegetable.cook();
mWashDishes.wash();
}
}
Client 類:
AbstractFacade abstractFacade = new NoodlesRestaurant();
abstractFacade.eat();
<h3> 優點 </h3>
- 屏蔽子系統,減少客戶端所需交互的對象,簡化調用
- 降低客戶端與子系統耦合,面對子系統變化,只需要調整外觀類即可
- 子系統間的修改不會相互影響
<h3> 缺點 </h3>
- 不能很好限制客戶端直接使用子系統類,對訪問子系統類做過多限制則減少可變性和靈活性
- 設計不當時,增加新的子系統需要修改外觀類源碼,違背開閉原則
<h3> 使用場景 </h3>
- 需要訪問一系列子系統完成業務需求
- 客戶端和多個子系統很高的耦合,使用外觀模式解耦,提高子系統的獨立性和可移植性
- 層次化結構中,使用外觀模式定義系統中每層的入口,層與層之間不直接產生聯系,通過外觀類建立聯系,降低層之間的耦合
源碼地址:Github