作為一個Android程式員,RecyclerView、ListView是平時開發中經常會使用到的,可以說是非常親切熟悉,而他們展現的設計模式正是擴充卡模式。
1 擴充卡模式概念
擴充卡模式(Adapter),将一個類的接口轉換成客戶希望的另外一個接口。Adapter模式使原本由于接口不相容而不能一起工作的那些類一起工作。
當系統的資料和行為都正确,但是接口不符時,我們應該考慮使用擴充卡,目的是使控制範圍之外的一個原有對象與某個接口比對。擴充卡模式主要應用于希望複用一些現存的類,但是接口又與複用環境要求不一緻的情況。
這裡大緻說一下擴充卡模式的使用場景:
- 系統需要使用現有的類,而此類的接口不符合系統的需要,即接口不相容
- 想要建立一個可以重複使用的類,用于與一些彼此之間沒有太大關聯的一些類,包括一些可能将來引進的類一起工作
- 需要一個統一的輸出接口,而輸入端的類型不可預知
而RecyclerView就很明顯是适用于上面的第一個場景:
RecyclerView
這個類需要在多個Activity、Fragment中展示不同的清單,但是我們用戶端隻有資料集,而RecyclerView怎麼可能直接根據我們的資料集來展示資料呢。是以我們重寫了
ReyclerView.Adapter<JavaBean>
,将資料進行了綁定,在任何場景,我們隻需要把這個 Adapter傳給RecyclerView,他就能展示我們想要的資料了。
RecyclerView.Adapter
連接配接了
RecyclerView
和
資料集
,将多種多樣的資料集,全部轉成可以被RecylerView所識别和展示的東西,這就展現出了擴充卡模式。
當然了,如果讀過Retrofit源碼,就會知道
Retrofit.create()
源碼中:
adapter()
會根據事先設定好的
CallAdapter
來适配并傳回不同的Call。
是以Retrofit的傳回可以适配像RxJava、RxAndroid這樣的情況。這裡就不多做細講,有興趣的可以自己檢視。
2. UML圖
來看下擴充卡模式的UML圖,它非常的簡單,我們甚至在了解RecyclerView後就能自己畫出來:
就是三大塊,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. 總結
可以看到,在上面寫翻譯類的時候,它的工作其實是讓真正别的類去做的,這有一點點像橋接模式,或者說,在這個場景下,它就是橋接模式。而且,翻譯類又像是别的類真正實作,這又有一點點像“外觀模式”。
可以看下這篇文章:設計模式學習筆記十四:擴充卡模式、橋接模式與外觀模式就講述的很清楚。
-
更好的複用性
系統需要使用現有的類,而此類的接口不符合系統的需要,那麼通過擴充卡模式就可以讓這些功能得到更好的應用。
-
更好的擴充性
在實作擴充卡功能的時候,可以調用自己開發的功能,進而自然地擴充系統的功能
- 過多的使用擴充卡,會讓系統非常淩亂,不易整體把握。例如,明明看到調用的是A接口,其實内部被适配成了B接口的實作,一個系統如果出現太多這種情況,無異于異常災難,是以,如果不是很有必要,可以不使用擴充卡,而是對系統進行重構。