天天看點

淺學設計模式之擴充卡模式(12/23)

作為一個Android程式員,RecyclerView、ListView是平時開發中經常會使用到的,可以說是非常親切熟悉,而他們展現的設計模式正是擴充卡模式。

1 擴充卡模式概念

擴充卡模式(Adapter),将一個類的接口轉換成客戶希望的另外一個接口。Adapter模式使原本由于接口不相容而不能一起工作的那些類一起工作。

當系統的資料和行為都正确,但是接口不符時,我們應該考慮使用擴充卡,目的是使控制範圍之外的一個原有對象與某個接口比對。擴充卡模式主要應用于希望複用一些現存的類,但是接口又與複用環境要求不一緻的情況。

這裡大緻說一下擴充卡模式的使用場景:

  1. 系統需要使用現有的類,而此類的接口不符合系統的需要,即接口不相容
  2. 想要建立一個可以重複使用的類,用于與一些彼此之間沒有太大關聯的一些類,包括一些可能将來引進的類一起工作
  3. 需要一個統一的輸出接口,而輸入端的類型不可預知

而RecyclerView就很明顯是适用于上面的第一個場景:

​​

​RecyclerView​

​​這個類需要在多個Activity、Fragment中展示不同的清單,但是我們用戶端隻有資料集,而RecyclerView怎麼可能直接根據我們的資料集來展示資料呢。是以我們重寫了 ​

​ReyclerView.Adapter<JavaBean>​

​,将資料進行了綁定,在任何場景,我們隻需要把這個 Adapter傳給RecyclerView,他就能展示我們想要的資料了。

​RecyclerView.Adapter​

​​連接配接了​

​RecyclerView​

​​和​

​資料集​

​,将多種多樣的資料集,全部轉成可以被RecylerView所識别和展示的東西,這就展現出了擴充卡模式。

當然了,如果讀過Retrofit源碼,就會知道​

​Retrofit.create()​

​源碼中:

淺學設計模式之擴充卡模式(12/23)

​adapter()​

​​會根據事先設定好的​

​CallAdapter​

​來适配并傳回不同的Call。

是以Retrofit的傳回可以适配像RxJava、RxAndroid這樣的情況。這裡就不多做細講,有興趣的可以自己檢視。

2. UML圖

來看下擴充卡模式的UML圖,它非常的簡單,我們甚至在了解RecyclerView後就能自己畫出來:

淺學設計模式之擴充卡模式(12/23)

就是三大塊,Target、Adapter、Adaptee。

在RecyclerView中,RecyclerView就是Target,RecyclerView.Adapter就是Adapter,資料集就是Adaptee。

3. 代碼示例

擴充卡模式又叫翻譯器模式,因為Adapter的作用就和“翻譯”差不多,這很适合一些需要翻譯的場景。

這裡是《大話》中的例子,現在的場景是NBA,姚主席剛來到NBA,還不會說英語,是以他需要一個翻譯,在沒有翻譯的時候,情況是這樣的:

//球員抽象類,定義了進攻和防守:
public abstract class Player {
    protected String name;

    public Player(String name) {
        this.name = name;
    }

    public abstract void offense();

    public abstract void defense();
}

// 具體球員類,分為前鋒、中鋒和後衛:
public class Forwards extends Player {
    public Forwards(String name) {
        super(name);
    }

    @Override
    public void offense() {
        System.out.println("前鋒" + name + "進攻");
    }

    @Override
    public void defense() {
        System.out.println("前鋒" + name + "防守");
    }
}

....//中鋒和後衛代碼類似,這裡省去

//用戶端代碼:
public class AdapterMain {
    public static void main(String[] args) {
        Player lbj = new Forwards("Lebron james");
        lbj.offense();
        Player kb = new Guards("Kobe Bryant");
        kb.offense();
    }
}      

這個時候,由于姚主席他并不适合Center,因為他并不知道attack和defense的意思,對于姚主席來說,他是一名外籍球員:

//外籍球員:
public class ForeignCenter {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 對中國人來說,隻知道進攻,不知道offense
    public void jingong() {
        System.out.println("外籍中鋒" + name + "進攻");
    }

    // 對中國人來說,隻知道防守,不知道defense
    public void fangshou() {
        System.out.println("外籍中鋒" + name + "防守");
    }
}      

這個時候就需要一個翻譯類來幫助姚主席:

//翻譯類
public class Translator extends Player {
    private ForeignCenter wjzf = new ForeignCenter();

    public Translator(String name) {
        super(name);
        wjzf.setName(name);
    }

    @Override
    public void offense() {
        wjzf.jingong();
    }

    @Override
    public void defense() {
        wjzf.fangshou();
    }
}      

翻譯類就是Adapter,它繼承了Player類,能調用offense,defense,在這些方法去調用外籍中鋒類的方法。

這樣,雖然使用的是 Translator,但是使用的是 ForeignCenter的方法。

// 用戶端代碼:
    public static void main(String[] args) {
        Player lbj = new Forwards("Lebron James");
        lbj.offense();
        Player kb = new Guards("Kobe Bryant");
        kb.offense();

        Player ym = new Translator("Yao Ming");
        ym.offense();
        ym.defense();
    }      

4. 總結

可以看到,在上面寫翻譯類的時候,它的工作其實是讓真正别的類去做的,這有一點點像橋接模式,或者說,在這個場景下,它就是橋接模式。而且,翻譯類又像是别的類真正實作,這又有一點點像“外觀模式”。

可以看下這篇文章:​​​設計模式學習筆記十四:擴充卡模式、橋接模式與外觀模式​​就講述的很清楚。

  1. 更好的複用性

    系統需要使用現有的類,而此類的接口不符合系統的需要,那麼通過擴充卡模式就可以讓這些功能得到更好的應用。

  2. 更好的擴充性

    在實作擴充卡功能的時候,可以調用自己開發的功能,進而自然地擴充系統的功能

  1. 過多的使用擴充卡,會讓系統非常淩亂,不易整體把握。例如,明明看到調用的是A接口,其實内部被适配成了B接口的實作,一個系統如果出現太多這種情況,無異于異常災難,是以,如果不是很有必要,可以不使用擴充卡,而是對系統進行重構。