23種設計模式之外觀模式

外觀模式在開發過程中的運用頻率非常高,通過一個外觀類使得整個系統的接口只有一個統一的高層接口,這樣能夠降低用戶的使用成本,也對用戶屏蔽了很多實現細節。

外觀模式的定義
要求一個子系統的外部與其內部的通信必須通過一個統一的對象進行。門面模式提供一個高層次的接口,使得子系統更易於使用。

外觀模式的使用場景

  • 爲一個複雜子系統提供一個簡單接口。
  • 當你需要構建一個層次結構的子系統時,使用Facade模式定義了子系統中每層的入口點。

外觀模式的UML類圖

這裏寫圖片描述

角色介紹
Facade:系統對外的統一接口,系統內部系統的工作。
SystemA、SystemB、SystemC:實現子系統的功能,並處理由Facade對象指派的任務。對子系統而言,facade和client角色是未知的,沒有Facade的任何相關信息;即沒有指向Facade的實例。

源碼的簡單示例

// 電話的接口
public interface Phone {
    // 打電話
    public void dail();
    // 掛斷
    public void hangup();
}

// 相機的接口
public interface Camera {
    public void open();
    public void takePicture();
    public void close();
}

// 手機的實現類
public class PhoneImpl implements Phone {
    @Override
    public void dail() {
        System.out.println("打電話");
    }

    @Override
    public void hangup() {
        System.out.println("掛斷");
    }
}

// 相機的實現類
public class SamsungCamera implements Camera {
    @Override
    public void open() {
        System.out.println("打開相機");
    }

    @Override
    public void takePicture() {
        System.out.println("拍照");
    }

    @Override
    public void close() {
        System.out.println("關閉相機");
    }
}

// Facade角色類
public class MobilePhone {
    private Phone mPhone = new PhoneImpl();
    private Camera mCamera = new SamsungCamera();

    public void dail(){
        mPhone.dail();
    }

    public void videoChat(){
        System.out.println("--> 視頻聊天接通中");
        mCamera.open();
        mPhone.dail();
    }

    public void hangup(){
        mPhone.hangup();
    }
    public void takePicture(){
        mCamera.open();
        mCamera.takePicture();
    }

    public void closeCamera(){
        mCamera.close();
    }
}

// 測試
public class Test {
    public static void main(String[] args){
        MobilePhone nexus6 = new MobilePhone();
        // 拍照
        nexus6.takePicture();
        // 視頻聊天
        nexus6.videoChat();
    }
}

測試結果:

打開相機
拍照
--> 視頻聊天接通中
打開相機
打電話

與其他相關模式

1)抽象工廠模式:Abstract Factory式可以與Facade模式一起使用以提供一個接口,這一接口可用來以一種子系統獨立的方式創建子系統對象。 Abstract Factory也可以代替Facade模式隱藏那些與平臺相關的類。

2)中介模式:Mediator模式與Facade模式的相似之處是,它抽象了一些已有的類的功能。然而,Mediator的目的是對同事之間的任意通訊進行抽象,通常集中不屬於任何單個對象的功能。
Mediator的同事對象知道中介者並與它通信,而不是直接與其他同類對象通信。相對而言,Facade模式僅對子系統對象的接口進行抽象,從而使它們更容易使用;它並不定義新功能,子系統也不知道Facade的存在。
通常來講,僅需要一個Facade對象,因此Facade對象通常屬於Singleton模式。

3)Adapter模式:
適配器模式是將一個接口通過適配來間接轉換爲另一個接口。
外觀模式的話,其主要是提供一個整潔的一致的接口給客戶端

總結
1)根據“單一職責原則”,在軟件中將一個系統劃分爲若干個子系統有利於降低整個系統的複雜性,一個常見的設計目標是使子系統間的通信和相互依賴關係達到最小,而達到該目標的途徑之一就是引入一個外觀對象,它爲子系統的訪問提供了一個簡單而單一的入口。

2)外觀模式也是“迪米特法則”的體現,通過引入一個新的外觀類可以降低原有系統的複雜度,外觀類充當了客戶類與子系統類之間的“第三者”,同時降低客戶類與子系統類的耦合度。外觀模式就是實現代碼重構以便達到“迪米特法則”要求的一個強有力的武器。

3)外觀模式要求一個子系統的外部與其內部的通信通過一個統一的外觀對象進行,外觀類將客戶端與子系統的內部複雜性分隔開,使得客戶端只需要與外觀對象打交道,而不需要與子系統內部的很多對象打交道。

4)外觀模式從很大程度上提高了客戶端使用的便捷性,使得客戶端無須關心子系統的工作細節,通過外觀角色即可調用相關功能。

5)不要試圖通過外觀類爲子系統增加新行爲 ,不要通過繼承一個外觀類在子系統中加入新的行爲,這種做法是錯誤的。外觀模式的用意是爲子系統提供一個集中化和簡化的溝通渠道,而不是向子系統加入新的行爲,新的行爲的增加應該通過修改原有子系統類或增加新的子系統類來實現,不能通過外觀類來實現。

優點
a. 對客戶程序隱藏子系統細節,因而減少了客戶對於子系統的耦合,能夠擁抱變化
b. 外觀類對子系統的接口封裝,使得系統更易於使用

缺點
a. 外觀類接口膨脹。由於子系統的接口都有外觀類統一對外暴露,使得外觀類的API接口較多,在一定程度上增加了用戶的使用成本。
b. 外觀類沒有遵循開閉原則,當業務出現變更時,可能需要直接修改外觀類。

模式擴展

一個系統有多個外觀類:
在外觀模式中,通常只需要一個外觀類,並且此外觀類只有一個實例,換言之它是一個單例類。在很多情況下爲了節約系統資源,一般將外觀類設計爲單例類。當然這並不意味着在整個系統裏只能有一個外觀類,在一個系統中可以設計多個外觀類,每個外觀類都負責和一些特定的子系統交互,向用戶提供相應的業務功能。
不要試圖通過外觀類爲子系統增加新行爲:
不要通過繼承一個外觀類在子系統中加入新的行爲,這種做法是錯誤的。外觀模式的用意是爲子系統提供一個集中化和簡化的溝通渠道,而不是向子系統加入新的行爲,新的行爲的增加應該通過修改原有子系統類或增加新的子系統類來實現,不能通過外觀類來實現。
外觀模式與迪米特法則:
外觀模式創造出一個外觀對象,將客戶端所涉及的屬於一個子系統的協作夥伴的數量減到最少,使得客戶端與子系統內部的對象的相互作用被外觀對象所取代。外觀類充當了客戶類與子系統類之間的“第三者”,降低了客戶類與子系統類之間的耦合度,外觀模式就是實現代碼重構以便達到“迪米特法則”要求的一個強有力的武器。

抽象外觀類的引入:

外觀模式最大的缺點在於違背了“開閉原則”,
當增加新的子系統或者移除子系統時需要修改外觀類,可以通過引入抽象外觀類在一定程度上解決該問題,客戶端針對抽象外觀類進行編程。對於新的業務需求,不修改原有外觀類,而對應增加一個新的具體外觀類,由新的具體外觀類來關聯新的子系統對象,同時通過修改配置文件來達到不修改源代碼並更換外觀類的目的。

UML類圖

這裏寫圖片描述

參考:http://blog.csdn.net/hguisu/article/details/7533759

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章