13.介面卡模式(Adapter Pattern)
1.定義
將一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠在一起工作。
介面卡模式又叫做變壓器模式。
2.介面卡模式的應用場景
介面卡模式應用的場景只要記住一點就足夠了:你有動機修改一個已經投產中的介面時,介面卡模式可能是最適合你的模式。比如系統擴充套件了,需要使用一個已有或新建立的類,但這個類又不符合系統的介面,怎麼辦?使用介面卡模式。
日常生活中也是經常能見到這樣的模式的,相信很多人都知道什麼是顯示卡,也有很多人知道顯示卡的本名——圖形介面卡。我們知道顯示器是用來顯示圖形的,它是不能顯示資料,它只能夠接受來自圖形傳送裝置的訊號。可是我們手頭上只有CPU這個產生各種描述圖形的資料的資料傳送器。我們需要將這些資料讓顯示器進行顯示,可是這兩個部件卻是不相容的。於是我們需要一個 中間裝置,它能夠將CPU“適配”於顯示器,這便是我們的顯示卡——圖形介面卡(Adapter)。
下面來看一個例子:
在我們日常開發中,經常要碰到和別的系統整合的問題。有時候兩個系統中描述同一個事物的Class定義卻不一樣,
比如我自己系統中的User物件是這樣定義的:
package _13AdapterPattern;
/**
* 目標系統的使用者介面
*/
public interface IUserInfo {
public String getName();
public String getCompanyAddress();
}
package _13AdapterPattern; /** * 目標系統的使用者實現類 */ public class TargetUserInfo implements IUserInfo { @Override public String getName() { System.out.println("張三"); return null; } @Override public String getCompanyAddress() { System.out.println("杭州"); return null; } }
而我要對接的第三方系統的使用者設計是這樣:
package _13AdapterPattern; import java.util.HashMap; import java.util.Map; /** * 第三方系統的使用者定義 */ public class SourceUserInfo { private Map<String, String> userInfoMap = new HashMap<String, String>(); public SourceUserInfo() { userInfoMap.put("userName", "張三"); userInfoMap.put("companyAddress", "杭州"); } public String getUserInfo(String key) { return userInfoMap.get(key); } }
這時候如果我呼叫第三方系統的webservice得到的使用者物件在我們系統中將不能執行,因為我們定義的完全不同。
那麼這時候該怎麼辦呢?
好吧,這個時候我想到去繼承它們的使用者類,並且實現自己的介面,這樣在拿到它們資料的同時,還能改裝成自己的使用者類:
package _13AdapterPattern;
/**
* 介面卡類,將第三方的使用者改裝成自己的使用者類
*/
public class AdapterUserInfo extends SourceUserInfo implements IUserInfo {
@Override
public String getName() {
// 將他們的獲取使用者資訊的API 封裝到我們自己的API中實現介面卡
return this.getUserInfo("userName");
}
@Override
public String getCompanyAddress() {
// TODO Auto-generated method stub
return this.getUserInfo("companyAddress");
}
}
這個AdapterUserInfo就是一個簡單實現的介面卡。
3.介面卡模式的三個角色
- Target目標角色
- Adaptee源角色
- Adapter介面卡角色
4.介面卡模式的優點
- 介面卡模式可以讓兩個沒有任何關係的類在一起執行,只要介面卡這個角色能夠搞定它們就行。
- 增加了類的透明性:想想看,我們訪問的目標角色,但是具體的實現都委託給了源角色,而這些對高層模組是透明的,也是它不需要關心的。
- 提高了類的複用度:源角色在原有的系統中還是可以正常使用,而在目標角色中也可以充當新的演員。
- 靈活性非常好:不想使用介面卡的時候,只要刪除介面卡就行了,其他程式碼基本不用修改。
5.介面卡模式的注意事項
介面卡模式最好在詳細設計階段不要考慮它,它不是為了解決還在開發階段的問題,而是解決正在服役的專案問題,沒有一個系統分析師會在做詳細設計的時候考慮使用介面卡模式。這個模式的主要使用場景是擴充套件應用中。
6.介面卡模式的擴充套件
介面卡模式分為兩種
- 型別介面卡:就是上面實現的那種,只要繼承源型別,並實現目標介面就行了
- 物件介面卡:我們把上例子中的介面卡重新實現以下,請看程式碼
package _13AdapterPattern;
/**
* 物件介面卡
*/
public class ObjectAdapterUserInfo implements IUserInfo {
private SourceUserInfo sourceUserInfo;
public ObjectAdapterUserInfo(SourceUserInfo sourceUserInfo)
{
this.sourceUserInfo = sourceUserInfo;
}
@Override
public String getName() {
return sourceUserInfo.getUserInfo("userName");
}
@Override
public String getCompanyAddress() {
return sourceUserInfo.getUserInfo("companyAddress");
}
}
看出來了吧,沒錯,我們只是把介面卡的繼承關係改成了組合關係,不過基於“組合優於繼承”的原則,大家懂的。