1.前言
其它的設(shè)計(jì)模式可能經(jīng)常用但卻不知道名字,但這篇文章所講的是那種,哪怕不知道原理也肯定聽過(guò)名字的模式咖杂。適配器對(duì)于安卓開發(fā)人員來(lái)說(shuō),是個(gè)耳熟能詳?shù)慕M件蜘犁。只要使用列表控件翰苫,必然會(huì)用到它來(lái)連接視圖和數(shù)據(jù)。大家都知道這兩者分屬View層和Model層这橙,通過(guò)接口與外部保持通信奏窑。若類型差距甚遠(yuǎn)的它們想要交互:
- 第一種方法就是改變各自的接口。先不說(shuō)View層基本由SDK提供API而不是源碼屈扎,就算Model層支持修改埃唯,但當(dāng)初定義接口是為了通用性,怎么可能一個(gè)應(yīng)用修改一次鹰晨。
- 第二種方法便是提供一個(gè)中間類墨叛,分別與兩個(gè)接口對(duì)接,起到轉(zhuǎn)換器的作用模蜡。就像不同齒距的齒輪漠趁,中間再加一個(gè)齒輪,就能協(xié)同工作了忍疾。
2.概念
適配器模式把一個(gè)類的接口變換成客戶端所期待的另一種接口闯传,從而使原本因接口不匹配而無(wú)法在一起工作的兩個(gè)類能夠在一起工作。通過(guò)學(xué)習(xí)《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》卤妒,知道以下兩種情況可以使用:
- 系統(tǒng)需使用現(xiàn)有的類甥绿,而此類的接口不符合要求,即接口不兼容则披;
- 想要建立一個(gè)可以重復(fù)使用的類(統(tǒng)一的輸出接口)共缕,用來(lái)與沒太大關(guān)聯(lián)且可能不斷引進(jìn)的類(輸入端的類型不可預(yù)知)一起工作,典型是列表的適配器士复。
3.場(chǎng)景
有一個(gè)人想喝酒图谷,他種了滿園的葡萄。雖然收獲到了葡萄但是自己不會(huì)釀酒判没,仍然喝不到酒蜓萄。后來(lái)附近開了酒廠,他把葡萄送過(guò)去加工澄峰,換來(lái)了等價(jià)的紅酒嫉沽。其中,酒廠就相當(dāng)于是適配器俏竞。
4.寫法
// 目標(biāo)或輸出接口
public interface Man {
void drink();
}
// 提供源接口或輸入端類型
public class Vineyard {
public String provide() {
return "葡萄";
}
}
// 適配器提供接口轉(zhuǎn)換
public class Winery extends Vineyard implements Man {
@Override
public void drink() {
switch (provide()) {
case "葡萄":
System.out.println("我喝到了紅酒");
break;
default:
System.out.println("我啥也沒喝到");
}
}
}
public class Main {
public static void main(String[] args) {
// 通過(guò)新建的酒廠喝到酒
new Winery().drink();
}
}
上面的代碼展示的是類適配器模式绸硕,即適配器類通過(guò)繼承源接口的實(shí)現(xiàn)類和實(shí)現(xiàn)目標(biāo)接口堂竟,來(lái)獲取輸入和輸出,并在內(nèi)部完成轉(zhuǎn)換玻佩。由于Java不支持多繼承出嘹,所以目標(biāo)接口不能用類替換。
通過(guò)前面的學(xué)習(xí)咬崔,知道可以用代理模式替換繼承關(guān)系税稼,即通過(guò)持有的對(duì)象來(lái)實(shí)現(xiàn)自己的行為。在保證邏輯的情況下垮斯,還能增加結(jié)構(gòu)的靈活性郎仆,同時(shí)避免了多繼承,允許目標(biāo)接口用類替換兜蠕,這便是對(duì)象適配器模式扰肌。
public class Winery implements Man {
// 持有源接口的對(duì)象
private Vineyard vineyard;
public Winery(Vineyard vineyard) {
this.vineyard = vineyard;
}
@Override
public void drink() {
switch (vineyard.provide()) {
case "葡萄":
System.out.println("我喝到了紅酒");
break;
default:
System.out.println("我啥也沒喝到");
}
}
}
public class Main {
public static void main(String[] args) {
// 通過(guò)新建的酒廠喝到酒
new Winery(new Vineyard()).drink();
}
}
這么改后,還發(fā)現(xiàn)了另一個(gè)好處熊杨。源接口中的方法不會(huì)暴露出來(lái)曙旭,即相比類適配器模式,適配器中少了繼承源接口后引入的多余方法晶府,降低用戶學(xué)習(xí)成本桂躏。
5.總結(jié)
在使用適配器模式時(shí),本著多用合成或聚合川陆,少用繼承的原則沼头。對(duì)于列表控件的適配器,即使子項(xiàng)View各種各樣书劝,它只要知道返回的是View類型即可,讓用戶來(lái)處理解析數(shù)據(jù)土至、綁定展示控件等操作购对。達(dá)到隔離變化、擁抱變化的目的陶因,也提高了代碼的復(fù)用性和擴(kuò)展性骡苞。