引入實例
說起適配器其實在我們的生活中是非常常見的,比如:學校的宿舍的電壓都比較低,而有的學生想使用大功率電器,宿舍的就會跳閘,然而如果你使用一個適配器(變壓器)就可以使用了(溫馨提示宿舍使用大功率電器不太安全,容易引起火災,希望大家謹慎使用)。
又比如說,有的插座都是三孔的,而我們用的大部分電器是兩孔的,這時我們可以使用一個適配器,適配器本身是三孔的,它可以直接插到三孔的插頭上,適配器本身可以提供一個兩孔的插座,然后我們就可以插到適配器上了,這樣我們原本只能插到兩孔上的插頭就能用三孔的插座了。
適配器模式的相關概念
適配器模式的正式定義
適配器模式(Adapter Pattern)是作為兩個不兼容的接口之間的橋梁。這種類型的設計模式屬于結構型模式,它結合了兩個獨立接口的功能。
適配器模式分為
- 類適配器模式
- 對象適配器模式
適配器模式的結構
適配器模式里面總共擁有三個角色,它們分別是:
- 目標(Target)接口:當前系統業務所期待的接口,它可以是抽象類或接口。
- 適配者(Adaptee)類:它是被訪問和適配的現存組件庫中的組件接口。
- 適配器(Adapter)類:它是一個轉換器,通過繼承(類適配器模式)或引用適配者的對象(對象適配器模式),把適配者接口轉換成目標接口(也就是使用轉換器將三頭的插座轉換成適合我們使用的兩頭插座),讓客戶按目標接口的格式訪問適配者。
注意事項:適配器不是在詳細設計時添加的,而是解決正在服役的項目的問題。
類適配器
類適配器的原理就是通過繼承來實現適配器功能。
讓Adapter實現Target接口,并且繼承Adaptee,這樣Adapter就具備Target和Adaptee的特性,就可以將兩者進行轉化。
舉例:以不同設備使用不同交流電為例,通過電源適配器進行轉換說明。
創建目標角色(Target)
public interface Target {int out();
}
創建源角色(Adaptee)
public class Adaptee{public int input() {System.out.println("輸入交流電: 220V");return 220;}
}
創建適配器(Adapter)
public class Adapter extends Adaptee implements Target {@Overridepublic int out() {int input220V = super.input();int output = input220V / 2;System.out.println("輸出交流電: " + output + "V");return output;}
}
客戶端調用
public static void main(String[] args) {Target adapter = new Adapter();int result = adapter.out();System.out.println(result);
}
輸入交流電: 220V
輸出交流電: 110V
110
對象適配器
對象適配器的原理就是通過組合來實現適配器功能。
讓Adapter實現Target接口,然后內部持有Adaptee實例,然后再Target接口規定的方法內轉換Adaptee。
創建目標角色(Target)
public interface Target {int out();
}
創建源角色(Adaptee)
public class Adaptee{public int input() {System.out.println("輸入交流電: 220V");return 220;}
}
創建適配器(Adapter)
public class Adapter implements Target {private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic int out() {int output = adaptee.input() / 2;System.out.println("輸出交流電: " + output + "V");return output;}
}
客戶端調用
public static void main(String[] args) {Target adapter = new Adapter(new Adaptee());int result = adapter.out();System.out.println(result);}
輸入交流電: 220V
輸出交流電: 110V
110
接口適配器
接口適配器的使用場景是解決接口方法過多,如果直接實現接口,那么類會多出許多空實現的方法,類顯得很臃腫。此時,使用接口適配器就能讓我們只實現我們需要的接口方法,目標更清晰。
接口適配器的主要原理就是原理利用抽象類實現接口,并且空實現接口眾多方法。
創建目標角色(Target)
public interface Target {int out1();int out2();int out3();int out4();
}
創建源角色(Adaptee)
public class Adaptee{public int input() {System.out.println("輸入交流電: 220V");return 220;}
}
創建適配器(Adapter)
public class Adapter implements Target {protected Adaptee adaptee;public Adapter(Adaptee adaptee){this.adaptee = adaptee;}@Overridepublic int out1() {int input220V = adaptee.input();int output = input220V / 1;System.out.println("輸出交流電: " + output + "V");return output;}@Overridepublic int out2() {int input220V = adaptee.input();int output = input220V / 2;System.out.println("輸出交流電: " + output + "V");return output;}@Overridepublic int out3() {return 0;}@Overridepublic int out4() {return 0;}
}
客戶端調用
public static void main(String[] args) {Target adapter = new Adapter(new Adaptee());adapter.out1();System.out.println("---------------------");adapter.out2();System.out.println("---------------------");Target adapter2 = new Adapter(new Adaptee()) {@Overridepublic int out3() {int input220V = adaptee.input();int output = input220V / 3;System.out.println("輸出交流電: " + output + "V");return output;}};adapter2.out3();System.out.println("---------------------");Target adapter3 = new Adapter(new Adaptee()) {@Overridepublic int out4() {int input220V = adaptee.input();int output = input220V / 4;System.out.println("輸出交流電: " + output + "V");return output;}};adapter3.out4();}
輸入交流電: 220V
輸出交流電: 220V
---------------------
輸入交流電: 220V
輸出交流電: 110V
---------------------
輸入交流電: 220V
輸出交流電: 73V
---------------------
輸入交流電: 220V
輸出交流電: 55V
優缺點
適配器模式優點:
- 可以讓任何兩個沒有關聯的類一起運行。
- 提高了類的復用。
- 增加了類的透明度。
- 靈活性好。
適配器模式缺點:
- 過多地使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是 A 接口,其實內部被適配成了 B 接口的實現,一個系統如果太多出現這種情況,無異于一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
- 由于 JAVA 至多繼承一個類,所以至多只能適配一個適配者類,而且目標類必須是抽象類。
優點 :
- 類適配器模式優點:由于適配器類是適配者類的子類,因此可以在適配器類中置換一些適配者的方法,使得適配器的靈活性更強。
- 對象適配器模式優點:一個對象適配器可以把多個不同的適配者適配到同一個目標,也就是說,同一個適配器可以把適配者類和它的子類都適配到目標接口。
缺點:
- 類適配器模式缺點:對于Java、C#等不支持多重繼承的語言,一次最多只能適配一個適配者類,而且目標抽象類只能為抽象類,不能為具體類,其使用有一定的局限性,不能將一個適配者類和它的子類都適配到目標接口。
- 對象適配器模式缺點:與類適配器模式相比,要想置換適配者類的方法就不容易。如果一定要置換掉適配者類的一個或多個方法,就只好先做一個適配者類的子類,將適配者類的方法置換掉,然后再把適配者類的子類當做真正的適配者進行適配,實現過程較為復雜。
類適配器和對象適配器的區別:
- 前者類之間的耦合度比后者高(這是因為類適配器模式使用的是繼承的方式,而對象適配器模式使用的是聚合或者組合的方式)。
- 類適配器模式要求程序員了解現有組件庫中的相關組件的內部結構,所以應用相對較少些,用的更多的還是對象適配器模式。
應用場景
- 當一個系統需要使用另一個系統的接口時,但是兩個系統的接口不兼容,可以使用適配器模式進行接口轉換。
- 在數據處理方面,適配器模式可以用于將不同格式的數據適配到一個標準的數據格式上。
- 當我們需要復用一些已有的類的時候,這些類的接口與我們需要的接口不兼容,可以使用適配器將這些類的接口轉換成我們需要的接口,從而實現類的復用。
- 適配器模式可以用于封裝有缺陷的接口設計,使得客戶可以通過適配器來使用這些缺陷的接口,而無需直接與其交互。
- 替換依賴的外部系統,使得系統可以在不修改源代碼的情況下適應新的外部系統。