標籤:
這篇部落格來介紹面板模式(Facade Pattern),面板模式也稱為門面模式,它在開發過程中運用頻率非常高,尤其是第三方 SDK 基本很大機率都會使用面板模式。通過一個外觀類使得整個子系統只有一個統一的高層的介面,這樣能夠降低使用者的使用成本,也對使用者屏蔽了很多實現細節。當然,在我們的開發過程中,面板模式也是我們封裝 API 的常用手段,例如網路模組、ImageLoader 模組等。其實我們在開發過程中可能已經使用過很多次面板模式,只是沒有從理論層面去瞭解它。
轉載請註明出處:http://blog.csdn.net/self_study/article/details/51931196。
PS:對技術感興趣的同鞋加群544645972一起交流。
設計模式總目錄
java/android 設計模式學習筆記目錄
特點
面板模式提供一個統一的介面,用來訪問子系統中的一群介面,外觀定義了一個高層介面,讓子系統更容易使用。
面板模式的使用情境:
- 為一個複雜子系統提供一個簡單介面。Facade 可以提供一個簡單統一的介面,對外隱藏子系統的具體實現、隔離變化。
- 當需要構建一個階層的子系統時,使用 Facade 模式定義子系統中每層的進入點。如果子系統之間是相互依賴,你可以讓他們僅通過 Facade 介面進行通訊,從而簡化了它們之間的依賴關係。
面板模式簡化了介面,並且同時允許我們讓用戶端和子系統之間避免緊耦合。
UML類圖
面板模式沒有一個一般化的類圖描述,我們先用一個結構圖來說明:
根據結構圖抽象出一個類圖:
面板模式有兩個角色:
- Facade 角色:系統對外的統一介面,用戶端串連子系統功能的入口。
- 子系統角色(SubSystem)角色:可以同時有一個或者多個子系統,每個子系統都不是一個單獨的類,而是一個類的集合。每個子系統都可以被用戶端直接調用,或者被門面角色調用。子系統並不知道門面的存在,對於子系統而言,門面僅僅是另外一個用戶端而已。
我們根據上面的 uml 類圖可以寫出面板模式的通用代碼:
子系統:
public class SystemA { public void operation1(){ System.out.print("SystemA:operation1\n"); } public void operation2(){ System.out.print("SystemA:operation2\n"); } public void operation3(){ System.out.print("SystemA:operation3\n"); }}
public class SystemB { public void operation1(){ System.out.print("SystemB:operation1\n"); } public void operation2(){ System.out.print("SystemB:operation2\n"); } public void operation3(){ System.out.print("SystemB:operation3\n"); }}
public class SystemC { public void operation1(){ System.out.print("SystemC:operation1\n"); } public void operation2(){ System.out.print("SystemC:operation2\n"); } public void operation3(){ System.out.print("SystemC:operation3\n"); }}
然後是外觀對象 IFacade.class
public interface IFacade { void operationA(); void operationB(); void operationC();}
Facade.class
public class Facade implements IFacade{ private SystemA systemA = new SystemA(); private SystemB systemB = new SystemB(); private SystemC systemC = new SystemC(); @Override public void operationA() { systemA.operation1(); systemB.operation2(); systemC.operation3(); } @Override public void operationB() { systemA.operation2(); systemB.operation1(); systemC.operation3(); } @Override public void operationC() { systemC.operation1(); systemB.operation2(); systemA.operation3(); }}
最後的測試代碼:
public static void main(String args[]) { IFacade facade = new Facade(); facade.operationA(); facade.operationB(); facade.operationC();}
結果輸出如下:
樣本與源碼
這裡直接展示一段簡單電腦啟動時的虛擬碼來表示即可:
/* Complex parts */class CPU { public void freeze() { ... } public void jump(long position) { ... } public void execute() { ... }}class Memory { public void load(long position, byte[] data) { ... }}class HardDrive { public byte[] read(long lba, int size) { ... }}/* Facade */class ComputerFacade { private CPU processor; private Memory ram; private HardDrive hd; public ComputerFacade() { this.processor = new CPU(); this.ram = new Memory(); this.hd = new HardDrive(); } public void start() { processor.freeze(); ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE)); processor.jump(BOOT_ADDRESS); processor.execute(); }}/* Client */class You { public static void main(String[] args) { ComputerFacade computer = new ComputerFacade(); computer.start(); }}
總結
面板模式是一個高頻率使用的設計模式,它的精髓就在於封裝二字。通過一個高階層為使用者提供統一的 API 入口,使得使用者通過一個類型就基本能夠操作整個系統,這樣減少了使用者的使用成本,也能夠提升系統的靈活性。
外觀類遵循了一個很重要設計模式原則:迪米特原則(最少知識原則),它讓用戶端依賴於最少的類,直接依賴外觀類而不是依賴於所有的子系統類。
優點:
- 對客戶程式隱藏子系統細節,因而減少了客戶對於子系統的耦合,能夠擁抱變化;
- 外觀類對子系統的介面封裝,使得系統更便於使用;
- 更好的劃分訪問層次,通過合理使用Facade,可以協助我們更好地劃分訪問的層次。有些方法是對系統外的,有些方法是系統內部使用的。把需要暴露給外部的功能集中到外觀類中,這樣既方便用戶端使用,也很好地隱藏了內部的細節。
缺點:
- 外觀類介面膨脹,由於子系統的介面都由外觀類統一對外暴露,使得外觀類的 API 介面較多,在一定程度上增加了使用者使用成本;
- 外觀類沒有遵循開閉原則,當業務出現變更時,可能需要直接修改外觀類。
適配器 VS 裝飾者 VS 橋接 VS 代理 VS 外觀
這幾個都是結構型設計模式,他們有些類似,在實際使用過程中也容易搞混,我們在這就給他們做一個對比:
適配器模式
適配器模式和其他三個設計模式一般不容易搞混,它的作用是將原來不相容的兩個類融合在一起,uml 圖也和其他的差別很大。
uml 類圖:
裝飾者模式
裝飾者模式結構上類似於代理模式,但是和代理模式的目的是不一樣的,裝飾者是用來動態地給一個對象添加一些額外的職責,裝飾者模式為對象加上行為,而代理則是控制訪問。
uml 類圖:
橋接模式
橋接模式的目的是為了將抽象部分與實現部分分離,使他們都可以獨立地進行變化,所以說他們兩個部分是獨立的,沒有實現自同一個介面,這是橋接模式與代理模式,裝飾者模式的區別。
uml 類圖:
代理模式
代理模式為另一個對象提供代表,以便控制客戶對對象的訪問,管理的方式有很多種,比如遠程代理和虛擬代理等,這個在上面有,這裡就不說了,而裝飾者模式則是為了擴充項物件。
uml 類圖:
面板模式
面板模式提供一個統一的介面,用來訪問子系統中的一群介面。外觀定義了一個高層介面,讓子系統更容易使用。
適配器模式將一個或多個類介面變成用戶端所期望的一個介面,雖然大多數資料所採用的例子中適配器只適配一個類,但是你可以適配許多類來提供一個介面讓用戶端訪問;類似的,面板模式 也可以只針對一個擁有複雜介面的類提供簡化的介面,兩種模式的差異,不在於他們“封裝”了幾個類,而是在於它們的意圖。適配器模式 的意圖是,“改變”介面符合客戶的期望;而面板模式的意圖是,提供子系統的一個簡化介面。
uml類圖:
源碼下載
https://github.com/zhaozepeng/Design-Patterns/tree/master/FacadePattern
引用
https://en.wikipedia.org/wiki/Facade_pattern
http://blog.csdn.net/jason0539/article/details/22775311
java/android 設計模式學習筆記(14)---面板模式