1. 程式人生 > 實用技巧 >設計模式——外觀模式

設計模式——外觀模式

外觀模式(Facade Pattern):隱藏系統的複雜性,並向客戶端提供了一個可以訪問系統的介面。這種型別的設計屬於結構型模式,它向現有的系統新增一個介面,來隱藏系統的複雜性。這種模式涉及到一個單一的類,該類提供了客戶端請求的簡化方法和對現有系統方法的委託呼叫。現實生活中,常常存在很多複雜的例子,例如:去醫院看病,可能要去掛號、門診、化驗、開藥、取藥,讓患者家屬覺得很複雜,如果有提供接待人員,只讓接待人員來處理,就很方便。或者 Java 的三層開發模式等等。軟體設計也是如此,當一個系統的功能越來越強,子系統會越來越多,客戶對系統的訪問也變得越來越複雜。這是如果系統內部發生改變,客戶端也要改變,違背了 “開閉原則” 和 “迪米特法則” 所以有必要為多個子系統提供一個統一的介面,從而降低系統的耦合度,這就是外觀模式。

一、 外觀模式的優點與缺點


外觀模式是 “迪米特法則” 的典型應用,優點如下:
1)、降低了子系統與客戶端之間的耦合度,使得子系統的變化不會影響呼叫它的客戶類,便於子系統內部維護和擴充套件。
2)、對客戶遮蔽了子系統元件,減少了客戶處理的物件數目,並使得子系統使用起來更加容易,降低了複雜性。
3)、降低了大型軟體系統中的編譯依賴性,簡化了系統在不同平臺之間的移植過程,因此編譯一個子系統不會影響其他子系統,也不會影響外觀物件。
4)、子系統也不會影響外觀系統。
5)、通過合理的使用外觀系統,可以更好的幫我們劃分訪問層次,當系統需要層次設計時,可以考慮外觀模式。
6)、在維護一個遺留的大型系統時,可能這個系統已經變得非常難以維護和擴充套件,此時可以考慮為新系統開發一個Facad類,來提供遺留系統的比較清晰簡單的介面,讓新系統與Facade類互動,提高複用性
7)、不能過多的或者不合理的使用外觀模式,使用外觀模式好,還是直接呼叫模組好。要以讓系統有層次,利於維護為目的。

外觀模式的主要缺點如下:
1)、不能很好地限制客戶端使用子類系統。
2)、增加了新的子類系統可能需要修改外觀類。

二、外觀模式結構類圖


外觀(Facade)模式的結構比較簡單,主要是定義了一個高層介面。它包含了對各個子系統的引用,客戶端可以通過訪問外觀類來訪問各個子系統的功能。

外觀模式主要包含一下三種角色:
【1】、外觀(Facade)角色:為多個子系統對外提供一個共同的介面。
【2】、子系統(Sub System)角色:實現系統的部分功能,客戶可以通過外觀角色訪問它。
【3】、客戶(Client)角色:通過一個外觀系統訪問各個子系統。

三、程式碼案例分析


【1】定義 CPU 、Hard、Memory 三大子系統之一:

通過懶漢式定義了例項化方法(genInstance())

 1 public class Memory {
 2     private static Memory memory = new Memory();
 3     public static Memory getInstance() {
 4         return memory;
 5     }
 6     
 7     public void open() {
 8         System.out.println("開啟記憶體");
 9     }
10     
11     public void down() {
12         System.out.println("關閉記憶體");
13     }
14 }

【2】定義外觀類:在構造器中通過呼叫子類的方法,例項化子類物件。

 1 public class Facade {
 2     private CPU cpu;
 3     private Memory memory;
 4     private Hard hard;
 5     //構造器 初始化子類例項
 6     public Facade() {
 7         super();
 8         this.cpu = CPU.getInstance();
 9         this.memory = Memory.getInstance();
10         this.hard = Hard.getInstance();
11     }
12     
13     //封裝所有開啟裝置
14     public void open() {
15         cpu.open();
16         hard.open();
17         memory.open();
18     }
19     //封裝所有關閉裝置
20     public void down() {
21         cpu.down();
22         hard.down();
23         memory.down();
24     }
25 }

【3】客戶端類:通過呼叫外觀類,實現對子類的呼叫

 1 public class Client {
 2     public static void main(String[] args) {
 3         //外觀類
 4         Facade facade = new Facade();
 5         //開啟電腦
 6         facade.open();
 7         //關閉電腦
 8         facade.down();
 9     }
10 }

四、外觀模式應用分析


外觀模式在 MyBatis 框架中應用的原始碼分析:

【1】MyBatis 中的 Configuration 去建立 MetaObject 物件使用到外觀模式

 1 public class Configuration {
 2     ......
 3   //建立子類例項
 4   protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
 5   protected ObjectFactory objectFactory = new DefaultObjectFactory();
 6   protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
 7 
 8   //封裝複雜的業務邏輯,返回客戶端需要的 MetaObject 
 9   public MetaObject newMetaObject(Object object) {
10     this.originalObject = object;
11     this.objectFactory = objectFactory;
12     this.objectWrapperFactory = objectWrapperFactory;
13     this.reflectorFactory = reflectorFactory;
14 
15     if (object instanceof ObjectWrapper) {
16       this.objectWrapper = (ObjectWrapper) object;
17     } else if (objectWrapperFactory.hasWrapperFor(object)) {
18       this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
19     } else if (object instanceof Map) {
20       this.objectWrapper = new MapWrapper(this, (Map) object);
21     } else if (object instanceof Collection) {
22       this.objectWrapper = new CollectionWrapper(this, (Collection) object);
23     } else {
24       this.objectWrapper = new BeanWrapper(this, object);
25     }
26   }

【2】上述外觀模式應用的類圖