擴充卡也屬于“接口隔離”模式的一種。
動機
- 在軟體系統中,由于應用環境的變化,常需要将“一些現存的對象”放在新的環境中應用,但是新環境要求的接口是對這些現存對象不滿足的。
- 如何應對這種“遷移的變化”?如何既能利用現有對象的良好實作,同時又能滿足新的應用環境所要求的接口?
生活中的Adapter

模式定義
将一個類的接口轉換成客戶希望的另一個接口。Adapter模式使得原本由于接口不相容而不能在一起工作的那些類可以一起工作。 —— 《設計模式》GOF
擴充卡模式的使用場景
- 使用一個已經存在的類,如果他的接口和你要求的不一緻時,可以考慮擴充卡模式;
- 要在調用者和功能提供者雙方都不太容易修改時再使用擴充卡模式,而不是一有不同就使用它。
UML類圖
類擴充卡
擴充卡Adapter繼承自Target和Adaptee類,Adapter類需要重寫Target類的Request函數,在Request中做适當的處理,調用Adaptee類的SepcificRequest。最終,Target實際調用的是Adaptee的SpecificRequest來完成Request的,完成适配;這種叫做類擴充卡。
對象擴充卡
擴充卡Adapter類繼承自Target類,同時,在Adapter類中有一個Adaptee類型的成員變量;Adapter類重寫Request函數時,在Request中,使用Adaptee類型的成員變量調用Adaptee的SpecificRequest函數,最終完成适配;這種叫做對象擴充卡。
類擴充卡和對象擴充卡的比較
既然有了類擴充卡和對象擴充卡,那麼在實際中如何在二者之間做選擇呢?
類擴充卡有以下特點:
對象擴充卡有以下特點:
- 由于Adapter直接繼承自Adaptee類,是以,在Adapter類中可以對Adaptee類的方法進行重定義;
- 如果在Adaptee中添加了一個抽象方法,那麼Adapter也要進行相應的改動,這樣就帶來高耦合;
- 如果Adaptee還有其它子類,而在Adapter中想調用Adaptee其它子類的方法時,使用類擴充卡是無法做到的。
由于對象擴充卡的耦合度比較低,是以在很多的書中都建議使用對象擴充卡。在我們實際項目中,也是如此,能使用對象組合的方式,就不使用多繼承的方式。
- 有的時候,你會發現,不是很容易去構造一個Adaptee類型的對象;
- 當Adaptee中添加新的抽象方法時,Adapter類不需要做任何調整,也能正确的進行動作;
- 可以使用多肽的方式在Adapter類中調用Adaptee類子類的方法。
對象擴充卡代碼實作
1 #include <iostream>
2 using namespace std;
3
4 class Target
5 {
6 public:
7 Target(){}
8 virtual ~Target(){}
9 virtual void Request()
10 {
11 cout<<"Target::Request"<<endl;
12 }
13 };
14
15 class Adaptee
16 {
17 public:
18 void SpecificRequest()
19 {
20 cout<<"Adaptee::SpecificRequest"<<endl;
21 }
22 };
23
24 class Adapter : public Target
25 {
26 public:
27 Adapter() : m_Adaptee(new Adaptee) {}
28
29 ~Adapter()
30 {
31 if (m_Adaptee != NULL)
32 {
33 delete m_Adaptee;
34 m_Adaptee = NULL;
35 }
36 }
37
38 void Request()
39 {
40 m_Adaptee->SpecificRequest();
41 }
42
43 private:
44 Adaptee *m_Adaptee;
45 };
46
47 int main(int argc, char *argv[])
48 {
49 Target *targetObj = new Adapter();
50 targetObj->Request();
51
52 delete targetObj;
53 targetObj = NULL;
54
55 return 0;
56 }
要點總結
- Adpater模式主要應用餘“希望複用一些現存的類,但是接口又與複用環境要求不一緻的情況”,在遺留代碼複用,類庫遷移等方面非常有用。
- GOF 23定義了對象擴充卡和類擴充卡,類擴充卡采用多繼承方式實作,一般不推薦。對象擴充卡采用對象組合方式,更符合松耦合精神。