對于擴充卡模式的四字概括,稱為“接口轉換”。
這裡的接口,并不特指java中的Interface. 而是一個廣義的概念,接口的概念可以了解為:一個程式,提供給外界可以通路的某個類的某個方法。接口以其唯一的命名為外界所知曉。唯一的命名包括全類名,及方法名,如全類名com.pattern.adapter.A,方法名doSth().
所謂接口轉換,就是說将如上的類轉換成其他類,将方法名改成其他的名稱(也可能隻改類名不改方法名),如類名改為com.pattern.adapter.B, 方法名改為doOther()。為什麼要這樣做?究竟怎麼轉換?請看下面例子。
假設我們的程式為客戶提供某個接口,以供客戶實作某種功能。我們稱之為目标接口。我們與客戶協商後決定,此目标接口将命名為com.pattern.adapter.Target(Target可能是一個Class或Interface,依據依賴抽象的原則,Target應盡可能是一個泛類型),方法名為doSth()。那麼客戶的程式中,将會從我們的程式得到一個Target對象,并調用此對象的doSth方法以實作某些功能。而我們的程式要做的,就是傳給客戶程式這樣的對象。
由于曆史原因,現在我們的程式中有一個類com.pattern.adapter.Stubborn,提供了方法do() ,此方法實作了與Target中doSth()方法所期望的相同的功能。我們希望提供給客戶一個Stubborn對象,并讓客戶調用do()方法實作其功能。這樣的話,用戶端代碼就得修改,比如用戶端代碼本來是這樣的:
Target t = getTarget(); //getTarget方法由我們提供
t.doSth();
現在我們要求客戶改為:
Stubborn s = getStubborn(); //getStubborn方法由我們提供
s.do();
但這顯然不太現實,我們的程式應該具有良好的相容性,而不是要求客戶修改其代碼。那麼我們要怎麼做?
如果我們可以将Stubborn變成Target,那不就OK了。
如果當初設計的時候,把Stubborn設計成Target的一個子類,或者實作類,現在就不需要這麼麻煩了。這樣Stubborn對象其實就是Target對象,也不會出現我們現在遇到的問題了。可他偏偏就不是。
我們何不現在就把Stubborn修改一下,讓他繼承Target(或實作Target,取決于Target是接口還是類),可以是可以,但是,根據開閉原則,我們應該盡量增加新的,而不是修改已有的。
好,我們的方案是這樣的:
1.不修改Stubborn。
2.增加一個新類,叫做com.pattern.adapter.Adapter. 讓Adapter繼承(或實作)Target,重寫doSth()方法,并且Adapter持有一個Stubborn對象的引用。重寫的doSth()方法調用Stubborn對象的do()方法。
3.建立Adapter對象,傳給客戶。
以下是Target,Stubborn,Adapter三個類型的源碼:
//
public Interface Target
{
public void doSth();
}
//
public class Stubborn
{
public void do()
{
//do something
}
}
//
public class Adapter implements Target
{
Stubborn origin;
public Adapter(Stubborn origin)
{
this.origin = origin;
}
@Override
public void doSth()
{
origin.do();
}
}
這樣,我們隻需要傳給用戶端一個Adapter對象(用戶端隻知道他是一個Target對象,并不知道他是一個Adapter對象,他也不需要知道),而用戶端的代碼不需要做任何改變。
還記得前面用戶端的代碼是怎麼寫的嗎? :
Target t = getTarget();
getTarget()是我們提供的方法,以下是此方法的重載實作:
public Target getTarget()
{
return new Adapter(new Stubborn());
}
至此,我們的擴充卡模式實作了将Stubborn轉換成Target。
以下是我們例子中擴充卡模式的類圖(為了使其看起來更符合擴充卡模式,我們将Stubborn的名稱改為Adaptee,表示被适配):
其實,擴充卡模式有兩種類型,我們剛才這個例子叫做對象擴充卡,還有一種叫做類擴充卡。
1. 對象擴充卡是将被适配的類型以對象組合的方式被擴充卡所引用,如我們剛才的做法是在Adapter類中,定義一個Stubborn類型的成員origin,然後doSth方法的實作其實是調用origin的do()方法。
2.類擴充卡是讓擴充卡繼承被适配的類型(即讓Adapter繼承Stubborn),具體做法情況如下Adapter類的類擴充卡實作源碼:
public class Adapter implements Target extends Stubborn
{
@Override
public void doSth()
{
do(); //do方法繼承自Stubborn
}
}
請将兩種方式中Adapter類的實作相比較。
類擴充卡對于java來說,有一個問題是如果Target也是Class而不是Interface,那麼Adapter就需要雙繼承,這在java就做不到了。
以下是擴充卡模式的定義:
“擴充卡模式将一個類的接口,轉換成客戶期望的另一個接口,擴充卡讓原本接口不相容的類可以合作無間” ---引用自《Head First設計模式》
好了,就寫到這,休息了,關于對象擴充卡和類擴充卡的比較,大家可以思考一下。