??????
《設計模式》中說道:將一個類的接口轉換成客戶希望的另一個接口。
Adapter
模式使得原本由于接口不兼容而不能一起工作的類可以一起工作。
??????
在實際的生活中有很多例子,如:我們常使用的移動硬盤,無論是筆記本硬盤還是臺式機硬盤,對于數據的傳輸都不使用
Usb
的數據線,外接的硬盤盒就是將原來的硬盤數據傳輸方式適合
Usb
數據線。(哎,我那個硬盤盒買的時候還
190
元,其實一點都不值,整個一個盒,就那個轉接芯片比較值錢,我說
50
,人家不賣)。
??????
我再接著說適配器模式,先舉個簡單的代碼例子,我現在要做一個隊列的類,實現先進先出的功能。利用
ArrayList
對象。
??????
首先,我們先定義一些隊列的接口,接口中定義隊列的方法,代碼如下:
??????
interface
IQueue
??? {
???????
void push(object item);???? //
進隊列
???????
object putout();??????????? //
出隊列
???????
object ShowLastItem();????? //
返回隊列中最后一項
???????
object ShowFirstItem();???? //
返回隊列中第一項
??? }
???
下面我們再來利用ArrayList對象實現一個隊列:
???
class Queue:IQueue
??? {
??????? ArrayList adaptee;
???????
???????
public Queue()
??????? {
??????????? adaptee = new ArrayList();
??????? }
???????
public
void push(object item)
??????? {
??????????? adaptee.Add(item);
??????? }
???????
public
object putout()
??????? {
???????????
object item = adaptee[0];
??????????? adaptee.RemoveAt(0);
???????????
return item;
??????? }
???????
public
object ShowLastItem()
??????? {
???????????
return adaptee[adaptee.Count-1];
??????? }
???????
public
object ShowFirstItem()
??????? {
???????????
return adaptee[0];
??????? }
??? }
???
實現有了,現在用客戶端程序調用來看一下結果:
???
class Class1
??? {
???????
///
<summary>
???????
///
應用程序的主入口點。
???????
///
</summary>
??????? [STAThread]
???????
static
void
??????? {
??????????? Queue queue = new Queue();
??????????? queue.push(1);
??????????? queue.push(2);
??????????? queue.push(3);
??????????? queue.push(4);
??????????? queue.push(5);
??????????? Console.Write("FirstItem:" + queue.ShowFirstItem().ToString() + "\n");
??????????? Console.Write("LastItem:" + queue.ShowLastItem().ToString() + "\n");
??????????? Console.Write("output:" + queue.putout().ToString() + "\n");
??????????? queue.push(6);
??????????? Console.Write("FirstItem:" + queue.ShowFirstItem().ToString() + "\n");
??????????? Console.Write("LastItem:" + queue.ShowLastItem().ToString() + "\n");
??????????? Console.Read();
??????? }
??? }
???
輸出結果:
??? FirstItem:1
LastItem:5
output:1
FirstItem:2
LastItem:6
適配器模式實現有兩種類型:對象適配器、類適配器。上面的代碼是對象適配器方式。也就是適配器(Queue)中是使用被適配(ArrayList)的對象實現。它的結構如下:
??? Gof
《設計模式》中提到了兩種Adapter適配器模式,一種叫對象適配器模式,另一種叫類適配器模式。對象適配器模式的結構如上圖,也就是我剛才舉的那個例子,那什么是類適配器模式呢?實際上類適配器模式就是讓Adapter的實現繼承Adaptee。換句話說:類適配器模式是以繼承的方式來實現,而對象適配器模式是以組合的方式實現。以前我們說過:繼承增加了模塊間的耦合程度,而組合降低了耦合程度,所以有人建議多使用對象適配器模式,少用類適配器模式。不過既然提到,我也具體談談類適配器模式。它的結構如下圖:
???
我們依然用上面的那個隊列的例子,首先我們要實現一個Adapter的類,這個類要繼承適配對象Adaptee類,也就是例子中的ArrayList,還有隊列接口,就是我們定義的IQueue,代碼如下:
???
class ClassAdapter:ArrayList,IQueue
??? {
???????
public ClassAdapter()
??????? {
???????????
??????? }
???????
public
void push(object item)
??????? {
???????????
this.Add(item);
??????? }
???????
public
object putout()
??????? {
???????????
object item = this[0];
???????????
this.RemoveAt(0);
???????????
return item;
??????? }
???????
public
object ShowLastItem()
??????? {
???????????
return
this[this.Count-1];
??????? }
???????
public
object ShowFirstItem()
??????? {
???????????
return
this[0];
??????? }
??? }
???
然后我們再修改一下客戶代碼:
???????
static
void
??????? {
??????????? ClassAdapter queue = new ClassAdapter();
??????????? queue.push(1);
??????????? queue.push(2);
??????????? queue.push(3);
??????????? queue.push(4);
??????????? queue.push(5);
??????????? Console.Write("FirstItem:" + queue.ShowFirstItem().ToString() + "\n");
??????????? Console.Write("LastItem:" + queue.ShowLastItem().ToString() + "\n");
??????????? Console.Write("output:" + queue.putout().ToString() + "\n");
??????????? queue.push(6);
??????????? Console.Write("FirstItem:" + queue.ShowFirstItem().ToString() + "\n");
??????????? Console.Write("LastItem:" + queue.ShowLastItem().ToString() + "\n");
??????????? Console.Read();
??????? }
???
輸出結果為:
FirstItem:1
LastItem:5
output:1
FirstItem:2
LastItem:6
要說明一點:從實現的代碼看:ClassAdapter類同時繼承了ArrayList,IQueue,這樣違反了設計原則中的單一職責原則(SRP)——一個類應該僅有一個引起他變化的原因。
接下來,我們在看看Adapter模式的幾個要點:
1、?????????????
Adapter
模式主要應用于“希望服用一些現存的類,但是接口又與復用環境要求不一致的情況”,在遺留代碼復用、類庫遷移等方面非常有用。
2、?????????????
Gof23
定義了兩種Adapter模式的實現結構:對象適配器和類適配器。但類適配器采用“多繼承”的實現方式,帶來了不良的高耦合,所以一般不推薦使用。對象適配器采用“對象組合”的方式,更符合松耦合精神。
3、?????????????
Adapter
模式本身要求我們盡可能的使用“面向接口的編程”風格,這樣才能在后期很方便的適配
Adapter
模式的實現方法有很多,說到這我在舉一個例子,我現在有這樣一個場景。我有一輛BORA車子和BMW的Engine和Wheel,我現在想改裝這輛BORA使其擁有BMW的Engine和Wheel,我如何做呢?
首先,我們要擁有一些BMW的零部件,代碼如下:
class
BMWPartClass
??? {
???????
public
void BMWEngine()
??????? {
??????????? Console.Write("It is a BMWEngine\n");
??????? }
???????
public
void BMWWheel()
??????? {
??????????? Console.Write("It is a BMWWheel\n");
??????? }
}
然后,再來實現對這些零部件的適配,代碼如下:
interface
ITarget
??? {
???????
void Request();
??? }
???
class Adapter:ITarget
??? {
??????? BMWPartClass adaptee = new BMWPartClass();
???????
public
void Request()
??????? {
??????????? adaptee.BMWEngine();
??????????? adaptee.BMWWheel();
??????? }
}
對于我的BORA的實現:
class
MyBORAClass
??? {
???????
public
void Process(ITarget target)
??????? {
??????????? target.Request();
??????? }
}
最后是客戶端代碼:
static
void
??????? {
??????????? MyBORAClass bora = new MyBORAClass();
??????????? bora.Process(new Adapter());
??????????? Console.Read();
??? }
輸出結果是:
It is a BMWEngine
It is a BMWWheel