適配器(adapter)模式:
適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。
生活中的場景:
1、筆記本電源適配器,可以將220v轉化為適合筆記本使用的電壓。
2、給筆記本電腦的usb接口插入臺式機的ps/2接口的鍵盤,需要一個usb和ps/2的接口轉接器,此時usb和ps/2的接口轉接器就充當了適配器的角色。
通用類圖:
在上面的通用類圖中,cient 類最終面對的是 target 接口(或抽象類),它只能夠使用符合這一目標標準的子類;而 adaptee 類則是被適配的對象(也稱 源角色),因為它包含specific (特殊的)操作、功能等,所以我們想要在自己的系統中使用它,將其轉換成符合我們標準的類,使得 client 類可以在透明的情況下任意選擇使用 concretetarget 類或是具有特殊功能的 adaptee 類。
適配器模式中的角色:
目標接口(target):客戶所期待得到的接口。目標可以是具體的或抽象的類,也可以是接口。
需要適配的類(adaptee):需要適配的接口或適配類。
適配器(adapter):適配器類是本模式的核心。適配器通過包裝一個需要適配的對象,把源接口轉換成目標接口。顯然,這一角色不可以是接口,而必須是具體類。
適配器模式的結構:
適配器模式有類的適配器模式和對象的適配器模式兩種不同的形式。
類的適配器模式把適配的類的api轉換成為目標類的api。
對象的適配器模式與類的適配器模式一樣,對象的適配器模式把被適配的類的api轉換成為目標類的api,與類的適配器模式不同的是,對象的適配器模式不是使用繼承關系連接到adaptee類,而是使用委派關系連接到adaptee類。
類的適配器模式
1、創建一個被適配的類:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** * 被適配的類 * 已存在的、具有特殊功能、但不符合我們既有的標準接口的類 * (相當于例子中的,ps/2鍵盤) * @author chuanchen * */ public class adaptee { public void specificrequest(){ system.out.println( "可以完成客戶請求的需要的功能!" ); } } |
2、創建一個目標接口,能處理一些特殊請求
1
2
3
4
5
6
7
8
|
/** * 目標接口,或稱為標準接口 * @author chuanchen * */ public interface target { void handlereq(); } |
3、創建一個適配器 (類適配器方式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/** * 適配器 (類適配器方式) * (相當于usb和ps/2的轉接器) * @author chuanchen * */ public class adapter extends adaptee implements target { @override public void handlereq() { super .specificrequest(); } } |
4、創建一個客戶端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/** * 客戶端類 * (相當于例子中的筆記本,只有usb接口) * @author chuanchen * */ public class client { public void test(target t){ t.handlereq(); } public static void main(string[] args) { client c = new client(); adaptee a = new adaptee(); target t = new adapter(); c.test(t); } } |
上面這種實現的適配器稱為類適配器,因為 adapter 類既繼承了 adaptee (被適配類),也實現了 target 接口(因為 java 不支持多繼承,所以這樣來實現),在 client 類中我們可以根據需要選擇并創建任一種符合需求的子類,來實現具體功能。
對象的適配器模式
1、創建一個被適配的類:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** * 被適配的類 * 已存在的、具有特殊功能、但不符合我們既有的標準接口的類 * (相當于例子中的,ps/2鍵盤) * @author chuanchen * */ public class adaptee { public void specificrequest(){ system.out.println( "可以完成客戶請求的需要的功能!" ); } } |
2、創建一個目標接口,能處理一些特殊請求
1
2
3
4
5
6
7
8
|
/** * 目標接口,或稱為標準接口 * @author chuanchen * */ public interface target { void handlereq(); } |
3、創建一個適配器 (對象適配器方式,使用了組合的方式跟被適配對象整合)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/** * 適配器 (對象適配器方式,使用了組合的方式跟被適配對象整合) * (相當于usb和ps/2的轉接器) * @author chuanchen * */ public class adapter implements target{ private adaptee adaptee; @override public void handlereq() { adaptee.specificrequest(); } public adapter(adaptee adaptee) { super (); this .adaptee = adaptee; } } |
4、創建一個客戶端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/** * 客戶端類 * (相當于例子中的筆記本,只有usb接口) * @author chuanchen * */ public class client { public void test(target t){ t.handlereq(); } public static void main(string[] args) { client c = new client(); adaptee a = new adaptee(); target t = new adapter(a); c.test(t); } } |
我們只需要修改 adapter 類的內部結構,即 adapter 自身必須先擁有一個被適配類的對象,再把具體的特殊功能委托給這個對象來實現。使用對象適配器模式,可以使得 adapter 類(適配類)根據傳入的 adaptee 對象達到適配多個不同被適配類的功能,當然,此時我們可以為多個被適配類提取出一個接口或抽象類。這樣看起來的話,似乎對象適配器模式更加靈活一點。
類適配器和對象適配器的權衡:
- 類適配器使用對象繼承的方式,是靜態的定義方式;而對象適配器使用對象組合的方式,是動態組合的方式。
- 對于類適配器,由于適配器直接繼承了adaptee,使得適配器不能和adaptee的子類一起工作,因為繼承是靜態的關系,當適配器繼承了adaptee后,就不可能再去處理 adaptee的子類了。
- 對于對象適配器,一個適配器可以把多種不同的源適配到同一個目標。換言之,同一個適配器可以把源類和它的子類都適配到目標接口。因為對象適配器采用的是對象組合的關系,只要對象類型正確,是不是子類都無所謂。
- 對于類適配器,適配器可以重定義adaptee的部分行為,相當于子類覆蓋父類的部分實現方法。
- 對于對象適配器,要重定義adaptee的行為比較困難,這種情況下,需要定義adaptee的子類來實現重定義,然后讓適配器組合子類。雖然重定義adaptee的行為比較困難,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時適用于所有的源。
- 對于類適配器,僅僅引入了一個對象,并不需要額外的引用來間接得到adaptee。
- 對于對象適配器,需要額外的引用來間接得到adaptee。
建議盡量使用對象適配器的實現方式,多用合成/聚合、少用繼承。當然,具體問題具體分析,根據需要來選用實現方式,最適合的才是最好的。
適配器模式的優點:
更好的復用性:
系統需要使用現有的類,而此類的接口不符合系統的需要。那么通過適配器模式就可以讓這些功能得到更好的復用。
更好的擴展性:
在實現適配器功能的時候,可以調用自己開發的功能,從而自然地擴展系統的功能。
適配器模式的缺點
過多的使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是a接口,其實內部被適配成了b接口的實現,一個系統如果太多出現這種情況,無異于一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
適配器模式在工作中的場景:
1、已經存在的類的接口不符合我們的需求;
2、創建一個可以復用的類,使得該類可以與其他不相關的類或不可預見的類(即那些接口可能不一定兼容的類)協同工作;
3、在不對每一個都進行子類化以匹配它們的接口的情況下,使用一些已經存在的子類。
適配器模式經常用于舊系統改造和升級。如果我們的系統開發之后再也不需要維護,那么很多模式都是沒有必要的。但是不幸的是,事實上維護一個系統的代價往往是開發一個系統的數倍。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/vae1314chuanchen/article/details/78207679