感謝《Android源碼設計模式解析與實戰》 何紅輝 關愛民 著
適配器模式在我們的開發中使用率極高,從代碼中隨處可見的Adapter就可以判斷出來,從最早的ListView、GridView、到現在最新的RecyclerView都需要使用Adapter,并且在開發中我們遇到的優化問題、出錯概率較大的地方也基本都出自Adapter。
適配器是將兩個不兼容的火龍融合在一起,將不同的東西通過一種轉換使得它們能夠協作起來,例如,經常碰到要在兩個沒有關系的類型之間進行交互,第一個解決方案是修改各自類的接口,但是如果沒有源代碼或者我們不愿意為了一個應用而修改各自的接口,這種情況我們往往會使用一個Adapter,這個Adapter會將這兩個接口進行兼容,在不修改原有代碼的情況下滿足需求。
假設已有一個軟件系統,你希望它能和一個新的廠商類庫搭配使用,但是這個新廠商所設計出來的接口,不用于舊廠商的接口:
你不想改變現有的代碼,解決這個問題(也不能改變廠商的代碼),應該怎么做?你可以寫一個類(適配器),將新廠商接口轉接成你所期望的接口,這個適配器工作起來就如同一個中間人,它將客戶所發出的請求轉換成廠商類能理解的請求。
適配器模式可分為兩種:
對象適配器:充滿著良好的OO設計原則,使用對象組合,可以應用在適配者是接口和它所有的子類,不能夠重寫適配器的方法,因為沒有繼承關系,但是也能夠“重新實現”適配者中方法,客戶端和適配者完全不相干,只有適配器擁有適配者的引用。
類適配器:使用繼承的方式達到適配的工作,只能是適配者是接口,不能利用它子類的接口,當類適配器建立時,它就靜態地與適配者關聯,適配者作為適配器的基類,所以適配器能夠重寫適配器中的方法,客戶端代碼對適配者中聲明的代碼是可見的客戶端代碼對適配者中聲明的代碼是可見的。
定義:
適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。
使用場景:
1.系統需要使用現有的類,而此類的接口不符合系統的需要,即接口不兼容。
2.想要建立一個可以重復使用的類,用于與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。
3.需要一個統一的輸出接口,而輸入端的類型不可預知。
UML類圖:
首先看下類適配器:
類適配器是通過實現Target接口以及繼承Adaptee類來實現接口轉換,例如,目標接口需要的是operation2,但是Adaptee對象只有一個operation3,因此就出現了不兼容的情況。此時通過Adapter實現一個operation2函數將Adaptee的operation3轉換成Target需要的operation2,以此實現兼容。
Target : 目標角色,也就是所期待得到的接口。注意:由于這里討論的是類適配器模式,因此目標不可以是類。
Adaptee : 現在需要適配的接口。
Adapter: 適配器角色,也是本模式的核心,適配器把源接口轉換成目標接口。這一角色不可以是接口,而必須是具體類。
類適配器模式示例:
以大陸電壓為220v,手機電壓為5v為例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
/** * 電壓類 Target目標 * @author Administrator * */ public interface Voltage { public int getVoltage(); } public class ChinaVoltage implements Voltage{ @Override public int getVoltage() { // 大陸電壓為220 return 220 ; } }<pre name= "code" class = "java" > /** * 手機類, Adaptee 被適配者類 * @author Administrator * */ public class PhoneVoltage { /** * 手機電壓為5v * @return */ public int getPhoneVoltage(){ return 5 ; } } <pre name= "code" class = "java" > /** * 充電器 Adapter 適配器類 * @author Administrator * */ public class Charger extends PhoneVoltage implements Voltage { @Override public int getVoltage() { return getPhoneVoltage(); } } public class Client { public static void main(String[] args) { ChinaVoltage vol = new ChinaVoltage(); System.out.println( "大陸電壓為 : " + vol.getVoltage()); //為手機接入充電器時的電壓 Chargerr character = new Chargerr(); System.out.println( "通過充電器轉換后的電壓 : " + character.getVoltage()); } } |
運行結果:
大陸電壓為 : 220
通過充電器轉換后的電壓 : 5
再看一下對象適配器類圖:
下面以對象適配器修改Chargerr類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<pre name= "code" class = "java" > /** * 充電器 Adapter 適配器類 * @author Administrator * */ public class Chargerr implements Voltage{ private PhoneVoltage phoneV; public Chargerr(PhoneVoltage phoneV) { this .phoneV = phoneV; } @Override public int getVoltage() { return phoneV.getPhoneVoltage(); } } |
對象適配器實現方式直接將要被適配的對象傳遞到Adapter中,使用組合的形式實現接口兼容的效果,這比類適配器方式更為靈活,它的另一個好處是被適配對象中的方法不會暴露出來,而類適配器由于繼承了被適配對象,因此,被適配對象類的函數在Adapter類中也都含有,這使得Adapter類出現一些奇怪的接口,用戶使用成本較高。因此,對象適配器模式更加靈活、實用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Client { public static void main(String[] args) { // ChinaVoltage vol = new ChinaVoltage(); // System.out.println("大陸電壓為 : " + vol.getVoltage()); // //為手機接入充電器時的電壓 // Chargerr character = new Chargerr(); // System.out.println("通過充電器轉換后的電壓 : " + character.getVoltage()); //被適配者 PhoneVoltage phoneV = new PhoneVoltage(); Chargerr chargerr = new Chargerr(phoneV); System.out.println( "通過充電器轉換后的電壓:" + chargerr.getVoltage()); } //運行結果: // 通過充電器轉換后的電壓:5 } |
總結:
Adapter模式的經典實現在于將原本不兼容的接口融合在一起,使之能夠很好地進行合作。但是,在實際開發中,Adapter模式也有一些靈活的實現。例如ListView中的隔離變化,使得整個UI架構變得更靈活,能夠擁抱變化。Adapter模式在開發呂運用非常廣泛。
優點:
更好的復用性:系統需要使用現有的類,而此類的接口不符合系統的需要。那么通過適配器模式就可以讓這些功能得到更好的復用。
更好的擴展性:在實現適配器功能的時候,可以調用自己開發的功能,從而自然地擴展系統的功能。
缺點:
過多的使用適配器,會讓系統非常零亂,不易速體把握。例如,明明看到調用的昌A接口,其實內部被適配成了B接口的實現,一個系統如果太多出現這種情況,無異于一場災難。因此,如果不是有必要,可以不使用適配器,而是直接對系統進行重構。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。