我所理解的設計模式(C++實現)——介面卡模式(Adapter Pattern)

LCL_data發表於2013-04-09

解決的問題:

介面卡模式把一個類的介面變換成客戶端所期待的另一種介面,從而使原本介面不匹配而無法在一起工作的兩個類能夠在一起工作。比如說我的hp筆記本,美國產品,人家美國的電壓是110V的,而我們中國的電壓是220V,要在中國能使用,必須找個變壓器轉一下電壓才可以。這個變壓器就是個介面卡。

介面卡模式有類介面卡和物件介面卡兩種模式,我們將分別討論。


類介面卡:

由圖中可以看出,Adaptee類沒有Request方法,而客戶期待這個方法。為了使客戶能夠使用Adaptee類,提供一箇中間環節,即類Adapter類,Adapter類實現了Target介面,並繼承自AdapteeAdapter類的Request方法重新封裝了AdapteeSpecificRequest方法,實現了適配的目的。

因為AdapterAdaptee是繼承的關係,所以這決定了這個介面卡模式是類的。

該介面卡模式所涉及的角色包括:

目標(Target)角色:這是客戶所期待的介面。因為C#不支援多繼承,所以Target必須是介面,不可以是類。
源(Adaptee)角色:需要適配的類。
介面卡(Adapter)角色:把源介面轉換成目標介面。這一角色必須是類

    簡單實現:

#include<iostream>
using namespace std;

// "ITarget"
class Target
{
public:
	// Methods
	virtual void Request(){};
};

// "Adaptee"
class Adaptee
{
public:
	// Methods
	void SpecificRequest()
	{
		cout<<"Called SpecificRequest()"<<endl;
	}
};

// "Adapter"
class Adapter : public Adaptee, public Target
{
public:
	// Implements ITarget interface
	void Request()
	{
		// Possibly do some data manipulation
		// and then call SpecificRequest  
		this->SpecificRequest();
	}
};


int main()
{
	// Create adapter and place a request
	Target *t = new Adapter();
	t->Request();

	return 0;
}

物件介面卡:

從圖中可以看出:客戶端需要呼叫Request方法,而Adaptee沒有該方法,為了使客戶端能夠使用Adaptee類,需要提供一個包裝(Wrapper)類Adapter。這個包裝類包裝了一個Adaptee的例項,從而將客戶端與Adaptee銜接起來。由於AdapterAdaptee是委派關係,這決定了這個介面卡模式是物件的。

該介面卡模式所涉及的角色包括:

目標(Target)角色:這是客戶所期待的介面。目標可以是具體的或抽象的類,也可以是介面。
源(Adaptee)角色:需要適配的類。
介面卡(Adapter)角色:通過在內部包裝(Wrap)一個Adaptee物件,把源介面轉換成目標介面。

簡單實現:

#include<iostream>
using namespace std;

// "ITarget"
class Target
{
public:
	// Methods
	virtual void Request(){};
};

// "Adaptee"
class Adaptee
{
public:
	// Methods
	void SpecificRequest()
	{
		cout<<"Called SpecificRequest()"<<endl;
	}
};

// "Adapter"
class Adapter : public Target
{
private:
	Adaptee *adaptee;

public:
	Adapter()
	{
		adaptee = new Adaptee();
	}

	// Implements ITarget interface
	void Request()
	{
		// Possibly do some data manipulation
		// and then call SpecificRequest  
		adaptee->SpecificRequest();
	}
};


int main()
{
	// Create adapter and place a request
	Target *t = new Adapter();
	t->Request();

	return 0;
}

預設介面卡:

預設介面卡模式是一種特殊的介面卡模式,但這個介面卡是由一個抽象類實現的,並且在抽象類中要實現目標介面中所規定的所有方法,但很多方法的實現都是平庸的實現,也就是說,這些方法都是空方法。而具體的子類都要繼承此抽象類。 

簡單實現:

#include<iostream>
using namespace std;


class Target { 
public:
	virtual void f1(){}; 
	virtual void f2(){}; 
	virtual void f3(){};   
};

class DefaultAdapter : public Target 
{ 
public:
    void f1() { 
    } 

    void f2() { 
    } 

    void f3() { 
    } 
};

class MyInteresting :public DefaultAdapter
{ 
public:
     void f3(){       
		cout<<"呵呵,我就對f3()方法感興趣,別的不管了!"<<endl;
    } 
};

int main()
{
	// Create adapter and place a request
	Target *t = new MyInteresting();
	t->f3();

	return 0;
}


實現要點:

1.Adapter模式主要應用於希望複用一些現存的類,但是介面又與複用環境要求不一致的情況,在遺留程式碼複用、類庫遷移等方面非常有用

2Adapter模式有物件介面卡和類介面卡兩種形式的實現結構,但是類介面卡採用多繼承的實現方式,帶來了不良的高耦合,所以一般不推薦使用。物件介面卡採用物件組合的方式,更符合鬆耦合精神。

3Adapter模式的實現可以非常的靈活,不必拘泥於GOF23中定義的兩種結構。例如,完全可以將Adapter模式中的現存物件作為新的介面方法引數,來達到適配的目的。

4Adapter模式本身要求我們儘可能地使用面向介面的程式設計風格,這樣才能在後期很方便的適配


使用場景:

在以下各種情況下使用介面卡模式:

1.系統需要使用現有的類,而此類的介面不符合系統的需要。

2.想要建立一個可以重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。這些源類不一定有很複雜的介面。

3.(對物件介面卡而言)在設計裡,需要改變多個已有子類的介面,如果使用類的介面卡模式,就要針對每一個子類做一個介面卡,而這不太實際。


LCL_data原創於CSDN.NET【http://blog.csdn.net/lcl_data/article/details/8780140


參考資料:

1.http://www.cnblogs.com/zhenyulu/articles/39386.html

2.http://www.cnblogs.com/Terrylee/archive/2006/02/18/333000.html


相關文章