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

外觀模式
- Facade(外觀角色):外觀角色中可以知道相關(guān)的多個(gè)子系統(tǒng)的功能和責(zé)任,客戶端調(diào)用它的方法,它再傳遞給相應(yīng)的子系統(tǒng)對(duì)象處理
- SubSystem(子系統(tǒng)角色):子系統(tǒng)可以不是單獨(dú)的類,而是類的集合,它實(shí)現(xiàn)子系統(tǒng)的功能,每個(gè)子系統(tǒng)都可以被客戶端直接調(diào)用,或者被外觀角色調(diào)用,對(duì)于子系統(tǒng)而言,外觀角色也是一個(gè)客戶端。

最近習(xí)慣了自己做飯,雖然做飯的過(guò)程很痛苦,可是看到自己做出來(lái)的美食后,還是很幸福很有成就感的。就拿自己做飯吃和去餐館吃飯來(lái)舉例,把餐館看做外觀角色,讓它把買菜、切菜、炒菜、刷碗這些工作統(tǒng)一組織起來(lái),我要做的就是告訴他要吃什么就行了,下面是示例代碼:
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 類:
// 自己做飯,需要跟這些子系統(tǒng)交互
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();
有了外觀模式,需要交互的類就變成了一個(gè),讓它負(fù)責(zé)和業(yè)務(wù)類實(shí)現(xiàn)交互,簡(jiǎn)化負(fù)責(zé)的交互,降低系統(tǒng)的耦合度,但是在標(biāo)準(zhǔn)的外觀模式中,如果需要增刪改外觀類交互的子系統(tǒng)類,就需要改動(dòng)客戶端源碼,這樣就違反了“開(kāi)閉原則”,因此遇到此類情況需要引入抽象外觀類進(jìn)行優(yōu)化,還以上面例子為基礎(chǔ):
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> 優(yōu)點(diǎn) </h3>
- 屏蔽子系統(tǒng),減少客戶端所需交互的對(duì)象,簡(jiǎn)化調(diào)用
- 降低客戶端與子系統(tǒng)耦合,面對(duì)子系統(tǒng)變化,只需要調(diào)整外觀類即可
- 子系統(tǒng)間的修改不會(huì)相互影響
<h3> 缺點(diǎn) </h3>
- 不能很好限制客戶端直接使用子系統(tǒng)類,對(duì)訪問(wèn)子系統(tǒng)類做過(guò)多限制則減少可變性和靈活性
- 設(shè)計(jì)不當(dāng)時(shí),增加新的子系統(tǒng)需要修改外觀類源碼,違背開(kāi)閉原則
<h3> 使用場(chǎng)景 </h3>
- 需要訪問(wèn)一系列子系統(tǒng)完成業(yè)務(wù)需求
- 客戶端和多個(gè)子系統(tǒng)很高的耦合,使用外觀模式解耦,提高子系統(tǒng)的獨(dú)立性和可移植性
- 層次化結(jié)構(gòu)中,使用外觀模式定義系統(tǒng)中每層的入口,層與層之間不直接產(chǎn)生聯(lián)系,通過(guò)外觀類建立聯(lián)系,降低層之間的耦合
源碼地址:Github