門面模式(Facade)是對象的結構模式,外部與一個子系統的通信必順通過一個統一的門面對象進行。門面模式提供一個高層次的接口,使得子系統更易于使用。 (參考)
門面模式的結構
由于門面模式的結構圖過于抽象,是以把它稍稍具體點。假設子系統内有三個子產品,分别是ModuleA, ModuleB, ModuleC,它們分别有一個示例方法,那麼此時示例的整體結構圖如下:
在這個對象圖中,出現了兩個角色:
- 門面(Facade)角色:
用戶端可以調用這個角色的方法。此角色知曉相關的(一個或者多個)子系統的功能和責任。在正常情況下,本角色會将所有從用戶端發來的請求委派到相應的子系統去。
- 子系統(SubSystem)角色:
可以同時有一個或者多個子系統。每個子系統都不是一個單獨的類,而是一個類的集合(如上面的子系統就是由ModuleA, ModuleB, ModuleC三個類組合而成)。每個子系統都可以被用戶端直接調用,或者被門面角色調用。子系統并不知道門面的存在,對于子系統而言,門面僅僅是另外一個用戶端而已。
門面模式的實作
使用門面模式還有一個附帶的好處,就是能夠有選擇性地暴露方法。一個子產品中定義的方法可以分成兩部分,一部分是給子系統外部使用的,一部分是子系統内部子產品之間互相調用時使用的。有了Facade類,那麼用于子系統内部子產品之間互相調用的方法就不用暴露給子系統外部了。
例如,定義如下a,b,c子產品:
package Facade
class Module {
/**
* 提供給子系統外部使用的
* */
fun a1(){
}
/**
* 提供給子系統内部使用的
* */
fun a2(){
}
fun a3(){
}
}
package Facade
class ModuleB {
/**
* 提供給子系統外部使用的
* */
fun b1(){
}
/**
* 提供給子系統内部使用的
* */
fun b2(){
}
fun b3(){
}
}
package Facade
class ModuleC {
/**
* 提供給子系統外部使用的
* */
fun c1(){
}
/**
* 提供給子系統内部使用的
* */
fun c2(){
}
fun c3(){
}
}
package Facade
class ModuleFacade {
val a = Module()
val b = ModuleB()
val c = ModuleC()
//下面這些是a,b,c子產品對子系統外部提供的方法
fun a1() {
a.a1()
}
fun b1() {
b.b1()
}
fun c1() {
c.c1()
}
}
這樣定義一個ModuleFacede類可以有效地屏蔽内部的細節,免得用戶端去調用Module類時,發現一些不需要它知道的方法。比如a2()和a3()方法就不需要讓用戶端知道,否則既暴露了内部的細節,又認用戶端迷惑。對用戶端來說,他可能還要去思考a2(),a3()方法用來做什麼呢?其它a2,a3()方法是内部子產品之間互動的,原本就不是對子系統外部的,是以就不要讓用戶端知道。
一個系統可以有幾個門面類
為子系統增加新行為
初學者往往以為通過繼承一個門面類便可在子系統中加入新的行為,這是錯誤的。門面模式的用意是為子系統提供一個集中化和簡化的溝通管道,而不能向子系統加入的新行為。
門面模式的優點
- 松散耦合
門面模式松散了用戶端與了系統的耦合關系,讓子系統内部的子產品能更容易擴充和維護。
- 簡單易用
門面模式讓子系統更加易用,用戶端不再需要了解子系統内部的實作,也不需要跟衆多子系統内部的子產品進行互動,隻需要跟門面類互動就可以了。
- 更好的劃分通路層次
通過合理使用Facade,可以幫助我們更好地劃分通路的層次。有些方法是對系統外的,有些方法是系統内部使用的。把需要暴露外部的功能集中到門面中,這樣既友善用戶端使用,也很好地隐藏了内部的細節。