Facade(外觀)模式為子系統中的各類(或結構與方法)提供一個簡明一致的介面,隱藏子系統的複雜性,使子系統更加容易使用。 使用facade以前
假設有五個類:propressor, compiler, assembler, linker, ar。分別負責gcc的五個步驟:先行編譯、編譯、彙編、連結、打包(參考《linux g++ 連結》)。
這五個步驟各自分工完成各自的工作,但它們之前又存在耦合。比如先行編譯、編譯、彙編、連結這四個步驟就是有循序關聯性的。它們必須被依次執行,才能得到正確的結果。
然而使用者並不關心它們之間是怎麼合作的,他們只希望使用一個gcc命令就能得到最終的可執行檔。
public class user { private target generateTarget(file source) { propressor cpp; compiler cc1; assembler as; linker ld; target i = cpp.propressing(source); target s = cc1.compilation(i); target o = as.assembly(s); target out = ld.linking(o); return out; } public void main(String[] args) { target exe = generateTarget(args[1]); }}
有時候,使用者只是想產生靜態庫和動態庫。
public class user { private target generateStaticLib(file source) { propressor cpp; compiler cc1; assembler as; ar ar; target i = cpp.propressing(source); target s = cc1.compilation(i); target o = as.assembly(s); target a = ar.ar(o); return a; } private target generateDynamicLib(file source) { propressor cpp; compiler cc1; assembler as; linker ld; target i = cpp.propressing(source); target s = cc1.compilation(i); target o = as.assembly(s); target so = ld.linkingWithPic(o); return so; } public void main(String[] args) { target lib1 = generateStaticLib(args[1]); target lib2 = generateDynamicLib(args[2]); }}
引入facade以後
如果你對gcc編譯連結的過程有一定的瞭解,一定能很容易地讀懂這幾個函數。
但是並不是每一個寫user的人都很清楚這個幾步驟的使用方式。
即使知道這些步驟,要求每個user都寫一遍也是件煩瑣的事情。
想像一下,如果沒有gcc命令,你想要 通過原始碼產生可執行檔或者庫,就不得不依次敲下cpp、cc1、as、ld、ar這幾個命令去產生。你一定寧願花幾分鐘寫個指令碼,把這幾個命令裝到一起,統一執行。
裝飾器的作用有點類似於這個指令碼。gcc過程中的幾個子系統,用法比較複雜,因此把常用的幾個種用法封裝成介面,以簡化使用者的使用。而對於特殊情況,也可以直接使用子系統。
public class gcc { public target generateTarget(file source) { propressor cpp; compiler cc1; assembler as; linker ld; target i = cpp.propressing(source); target s = cc1.compilation(i); target o = as.assembly(s); target out = ld.linking(o); return out; } public target generateStaticLib(file source) { propressor cpp; compiler cc1; assembler as; ar ar; target i = cpp.propressing(source); target s = cc1.compilation(i); target o = as.assembly(s); target a = ar.ar(o); return a; } public target generateDynamicLib(file source) { propressor cpp; compiler cc1; assembler as; linker ld; target i = cpp.propressing(source); target s = cc1.compilation(i); target o = as.assembly(s); target so = ld.linkingWithPic(o); return so; }}public class user { public static void main(String[] args) { gcc g; target out = g.generateTarget(args[1]); target lib1 = generateStaticLib(args[2]); target lib2 = generateDynamicLib(args[3]); target i = cpp.propressing(source); }}
用後感
一個面板模式寫完了,現在分析一下它起到的作用。 1.外觀gcc為複雜的子系統propressor, compiler, assembler, linker, ar提供了簡單的介面。使用者不需要理解子系統之間的關係就可以理解gcc提供的功能。 2.這幾個子系統的功能相關,耦合性比較高,子系統之間的關係發生變化的可能性比較大,但所提供功能變化的可能性不大。當子系統之間發生了變化,而功能未變時,只需要修改外觀gcc即可,使用者代碼不需要修改。 3.對於特殊情況,也可以直接使用子系統,保持了原來的靈活性。
在有些情況下,它能起到積極的作用,有些情況可能會帶來相反的效果。每一種模式都有它的適用情境。 1.多個類為同一個功能服務,它們之間耦合較高,使用複雜。 2.多個類之間的關係經常發生變化。 3.多個類互相配合使用的方法中,有些常用搭配。 4.使用者通常不關心幾個類之間的配合。