二十二、外觀設計模式

1. 外觀設計模式介紹

顯示生活中有一個種電視萬能遙控器,只要和電視配對好了以後,就可以正常使用,不同型號的電視,只要一旦適配,所有的操作模式一模一樣。

這就是一種外觀適配模式。表面上都是同一個遙控器,實際上不同型號的電視,不同的操作,發出的型號可能各不相同。但是對於用戶來說,沒有任何差別。

定義

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

2. 外觀設計模式使用場景

  • 爲一個複雜的子系統提供簡單、固定的接口。比如我們常用的加載圖片的框架,隨着項目的推進,框架沒有人維護,或者出現了效率更高的框架出現,此時如果項目進行更換框架,可能需要修改很多處。如果,項目特別大,更是災難。但是如果我們之前採用了外觀設計模式,設計了統一的封裝接口,我們只需要接口裏面詳細的邏輯即可,而不必修改很多出。從外觀就好像沒有修改一樣。

  • 當構建一個層次結構的子系統時,使用外觀設計模式定義子系統中每層的入口點。如果子系統之間是相互依賴的,那麼子系統之間可以通過外觀設計模式定義的接口進行通訊,簡化子系統之間的依賴關係。

3. 外觀設計模式UML類圖

外觀設計模式UML類圖

4. 外觀設計模式簡單實例

現在以一個情形:一個子系統擁有三個模塊,每個模塊都有三個方法,其中一個爲客戶端調用方法,其它兩個爲各個子模塊間互相調用方法。此時客戶端需要組合三個模塊中的方法才能完成功能。

  • (1)、A、B、C三個模塊方法:

A 模塊方法接口:

public interface AModuleApi {
    //此方法用於外部調用
    public void a1();
    //以下兩個方法主要用於子系統內部間系統調用
    public void a2();
    public void a3();
}

A模塊具體實現:

public class AModuleImpl implements AModuleApi {
    @Override
    public void a1() {
        System.out.println("調用了A模塊");
    }

    @Override
    public void a2() {
        //主要用於子模塊間相互調用
    }

    @Override
    public void a3() {
        // 主要用於子模塊間相互調用
    }
}

以上是A模塊中的方法,B、C兩個模塊和A一樣。

  • (2)、不採用外觀設計模式,客戶端如下:
public class Client {
    public static void main(String[] args) {

        AModuleApi aModule = new AModuleImpl();
        aModule.a1();

        BModuleApi bModule = new BModuleImpl();
        bModule.b1();

        CModuleImpl cModule = new CModuleImpl();
        cModule.c1();
    }
}

上面的代碼我們會經常寫,自習詳細,會存在如下問題:

  • 代碼耦合度太高,客戶端與子系統中各模塊都有關聯。一旦子系統有什麼更改,會涉及到客戶端的修改。

  • 客戶端想要知道每個模塊中各個方法的含義才能進行調用。

現在採用了外觀設計模式,添加一個外觀類,由外觀重組需要調用的方法

  • (3)、添加一個外觀類接口:
public interface FacadeApi {
    public void a1();

    public void b1();

    public void c1();

    public void test();
}
  • (4)、外觀類的具體實現:
public class FacadeImpl implements FacadeApi {
    @Override
    public void a1() {
        new AModuleImpl().a1();
    }

    @Override
    public void b1() {
        new BModuleImpl().b1();
    }

    @Override
    public void c1() {
        new CModuleImpl().c1();
    }

    @Override
    public void test() {
        a1();
        b1();
        c1();
    }
}

在test方法中,調用了三個模塊中的方法。外觀類是在服務端的,不是這客戶端。客戶端不需要知道具體的內部實現是什麼樣的。

  • (5)、客戶端:
public class Client {
    public static void main(String[] args) {
        /**
         * 直接調用外觀類裏面的方法就可以了,內部細節不用知道,
         * 計算改變了,也只需要調用這兩行代碼即可。
         */
        FacadeApi facade = new FacadeImpl();
        facade.test();
    }
}

客戶端只需要調用外觀模式中的代碼即可,不需要關注具體實現細節。

5. 外觀設計模式在Android源碼

我們經常在Activity中調用其他的方法,比如,Activity的跳轉,發送廣播,啓動服務等。這些方法都是封裝在Context類中,Context是一個抽象類,具體實現是ContextImpl。

ContextImpl內部封裝了很多不同子系統的操作,上面說的這些操作就是在這裏面,然後它的具體實現並不在ContextImpl裏面,而是在各個不同的子系統進行處理。

這張圖就是ContextImpl和各個子類系統之間的調用關係:

外觀設計模式-android系統

6. 外觀設計模式在Android開發中

在開發中,我們經常會用到圖片加載,網絡加載框架。有時候,隨着時間的推移,我們所使用框架的作者有可能不再維護,或者出現了效率更高的新的框架。

這時如果我們想要修改爲新的框架,可能比較困難,可能太多的地方用到了。

但是如果我們採用了外觀設計模式,用了一個外觀類來包裝,調用的時候直接調用外觀方法,而不是直接調用。以後在需要修改的時候,只需要修改包裝類的方法即可。

實例:

public class ImageLoaer {

    public Image loadImage(String url, int width, int height) {
        //調用具體的圖片框架方法加載
    }
}

7. 總結

  • 優點:
    • 對客戶端程序隱藏子系統細節,減少了客戶端對子系統的耦合。
    • 外觀類對子系統的封裝,使得系統更易於使用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章