1、什麼是介面卡模式?
Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
介面卡模式(Adapter Pattern):將一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠在一起工作。
說人話:這個模式就是用來做適配的,它將不相容的介面轉換為可相容的介面,讓原本由於介面不相容而不能一起工作的類可以一起工作。比如現實生活中的例子, USB 轉接頭就充當介面卡,把兩種不相容的介面,通過轉接變得可以一起工作。
2、介面卡模式定義
①、Target目標角色
該角色定義把其他類轉換為何種介面, 也就是我們的期望介面, 例子中的IUserInfo介面就是目標角色。
②、Adaptee源角色
你想把誰轉換成目標角色, 這個“誰”就是源角色, 它是已經存在的、 執行良好的類或物件, 經過介面卡角色的包裝, 它會成為一個嶄新、 靚麗的角色。
③、Adapter介面卡角色
介面卡模式的核心角色, 其他兩個角色都是已經存在的角色, 而介面卡角色是需要新建立的, 它的職責非常簡單: 把源角色轉換為目標角色, 怎麼轉換? 通過繼承或是類關聯的方式。
3、介面卡模式通用程式碼實現
/**
* 目標角色
*/
public interface Target {
void t1();
void t2();
void t3();
}
/**
* 目標角色實現類
*/
public class ConcreteTarget implements Target{
@Override
public void t1() {
System.out.println("目標角色 t1 方法");
}
@Override
public void t2() {
System.out.println("目標角色 t2 方法");
}
@Override
public void t3() {
System.out.println("目標角色 t3 方法");
}
}
/**
* 源角色:要把源角色轉換成目標角色
*/
public class Adaptee {
public void a1(){
System.out.println("源角色 a1 方法");
}
public void a2(){
System.out.println("源角色 a2 方法");
}
public void a3(){
System.out.println("源角色 a3 方法");
}
}
基於繼承的類介面卡
/**
* 介面卡角色
*/
public class Adapter extends Adaptee implements Target{
@Override
public void t1() {
super.a1();
}
@Override
public void t2() {
super.a2();
}
@Override
public void t3() {
super.a3();
}
}
基於組合的物件介面卡
public class AdapterCompose implements Target{
private Adaptee adaptee;
public AdapterCompose(Adaptee adaptee){
this.adaptee = adaptee;
}
@Override
public void t1() {
adaptee.a1();
}
@Override
public void t2() {
adaptee.a2();
}
@Override
public void t3() {
adaptee.a3();
}
}
測試:
public class AdapterClient {
public static void main(String[] args) {
// 原有的業務邏輯
Target target = new ConcreteTarget();
target.t1();
// 基於繼承 增加介面卡業務邏輯
Target target1 = new Adapter();
target1.t1();
// 基於組合 增加介面卡業務邏輯
Target target2 = new AdapterCompose(new Adaptee());
target2.t1();
}
}
列印結果:
介面卡模式有兩種實現方式:類介面卡和物件介面卡。其中,類介面卡使用繼承關係來實現,物件介面卡使用組合關係來實現。在實際開發中,選擇的依據如下:
①、如果 Adaptee 介面並不多,那兩種實現方式都可以。
②、如果 Adaptee 介面很多,而且 Adaptee 和 ITarget 介面定義大部分都相同,那我們推薦使用類介面卡,因為 Adaptor 複用父類 Adaptee 的介面,比起物件介面卡的實現方式,Adaptor 的程式碼量要少一些。
③、如果 Adaptee 介面很多,而且 Adaptee 和 ITarget 介面定義大部分都不相同,那我們推薦使用物件介面卡,因為組合結構相對於繼承更加靈活。
4、介面卡模式優點
①、介面卡模式可以讓兩個沒有任何關係的類在一起執行, 只要介面卡這個角色能夠搞定他們就成。
②、增加了類的透明性
我們訪問的Target目標角色, 但是具體的實現都委託給了源角色, 而這些對高層次模組是透明的, 也是它不需要關心的。
③、提高了類的複用度
源角色在原有的系統中還是可以正常使用, 而在目標角色中也可以充當新的演員。
④、靈活性非常好
介面卡可以隨時去掉,而不會影響很多程式碼。
5、介面卡模式應用場景
①、修改已使用的介面
某個已經投產中的介面需要修改,這時候使用介面卡最好。
②、統一多個類的介面設計
比如對於敏感詞過濾,需要呼叫好幾個第三方介面,每個介面方法名,方法引數又不一樣,這時候使用介面卡模式,將所有第三方的介面適配為統一的介面定義。
③、相容老版本介面
比如JDK1.0 中包含一個遍歷集合容器的類 Enumeration,JDK2.0 對這個類進行了重構,將它改名為 Iterator 類,並且對它的程式碼實現做了優化。但是考慮到如果將 Enumeration 直接從 JDK2.0 中刪除,那使用 JDK1.0 的專案如果切換到 JDK2.0,程式碼就會編譯不通過。為了避免這種情況的發生,我們必須把專案中所有使用到 Enumeration 的地方,都修改為使用 Iterator 才行。
單獨一個專案做 Enumeration 到 Iterator 的替換,勉強還能接受。但是,使用 Java 開發的專案太多了,一次 JDK 的升級,導致所有的專案不做程式碼修改就會編譯報錯,這顯然是不合理的。這就是我們經常所說的不相容升級。為了做到相容使用低版本 JDK 的老程式碼,我們可以暫時保留 Enumeration 類,並將其實現替換為直接呼叫 Itertor。
public class Collections {
public static Emueration emumeration(final Collection c) {
return new Enumeration() {
Iterator i = c.iterator();
public boolean hasMoreElments() {
return i.hashNext();
}
public Object nextElement() {
return i.next():
}
}
}
}
④、適配不同格式的資料
6、代理-橋接-裝飾器-介面卡區別
①、代理模式在不改變原始類介面的條件下,為原始類定義一個代理類,主要目的是控制訪問,而非加強功能,這是它跟裝飾器模式最大的不同。
②、橋接模式:橋接模式的目的是將介面部分和實現部分分離,從而讓它們可以較為容易、也相對獨立地加以改變。
③、裝飾器模式:裝飾者模式在不改變原始類介面的情況下,對原始類功能進行增強,並且支援多個裝飾器的巢狀使用。
④、介面卡模式:介面卡模式是一種事後的補救策略。介面卡提供跟原始類不同的介面,而代理模式、裝飾器模式提供的都是跟原始類相同的介面。