適配器模式(Adapter Pattern)詳解
一、適配器模式簡介
適配器模式是一種結構型設計模式,它將一個類的接口轉換成客戶端所期望的另一個接口。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以協同工作。
簡單來說,適配器模式就像是一個變壓器或者轉接頭,它可以幫助我們解決兩個不兼容接口之間的合作問題。
別名為**包裝器(Wrapper)**模式。
定義中所提及的接口是指廣義的接口,它可以表示一個方法或者方法的集合。
二、適用場景與針對的問題
- 適用場景:當你需要使用一個已有的類,但是它的接口并不符合你的需求時;或者你需要創建一個可復用的類,該類能夠與其他不相關的類或不可預見的類(即那些接口可能不一定兼容的類)協同工作。
- 針對的問題:主要是解決不同接口之間的不兼容性問題,使得它們能夠在不影響各自實現的情況下進行協作。
三、實際案例
想象一下,你有一臺筆記本電腦和一部手機,兩者都需要充電,但它們的充電插口不一樣。如果你只有一個電源適配器,這個適配器能將家用電源轉換為筆記本電腦所需的電壓和電流類型,但對于手機則無法直接使用。此時,你就需要一個USB-C到Lightning的適配器來為你的手機充電。這里,電源適配器和USB-C到Lightning適配器就起到了適配器的作用。
3.1 適配器模式的結構與實現
適配器模式的結構(類適配器)
適配器模式的結構(對象適配器)
適配器模式的結構
適配器模式包含以下3個角色:
Target(目標抽象類)
Adapter(適配器類)
Adaptee(適配者類)
四、代碼案例
假設有一個MediaPlayer
接口和其實現類AudioPlayer
,它只能播放mp3格式的音頻文件。現在我們需要擴展其功能以支持更多格式如VLC和MP4,但不想改變原有的AudioPlayer
類。這時就可以使用適配器模式。
// 目標接口
interface MediaPlayer {public void play(String audioType, String fileName);
}// 已有類,實現了不同的接口
class AdvancedMediaPlayer {public void playVlc(String fileName) {System.out.println("Playing vlc file. Name: " + fileName);}public void playMp4(String fileName) {System.out.println("Playing mp4 file. Name: " + fileName);}
}// 適配器類
class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer = new AdvancedMediaPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer = new AdvancedMediaPlayer();}}@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer.playMp4(fileName);}}
}// 使用適配器的類
class AudioPlayer implements MediaPlayer {MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {System.out.println("Playing mp3 file. Name: " + fileName);} else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);} else {System.out.println("Invalid media. " + audioType + " format not supported");}}
}// 測試類
public class Test {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "beyond the horizon.mp3");audioPlayer.play("mp4", "alone.mp4");audioPlayer.play("vlc", "far far away.vlc");audioPlayer.play("avi", "mind me.avi");}
}
在這個例子中,MediaAdapter
充當了適配器的角色,它將AdvancedMediaPlayer
的功能適配到了MediaPlayer
接口上,從而解決了接口不兼容的問題。通過這種方式,我們可以輕松地擴展AudioPlayer
的功能,讓它支持更多的音頻格式。
五、缺省適配器模式
- 定義:當不需要實現一個接口所提供的所有方法時,可先設計一個抽象類實現該接口,并為接口中每個方法提供一個默認實現(空方法),那么該抽象類的子類可以選擇性地覆蓋父類的某些方法來實現需求,它適用于不想使用一個接口中的所有方法的情況,又稱為單接口適配器模式。
- 結構:
- 實現:
缺省適配器類的典型代碼片段(C++):
abstract class AbstractServiceClass : ServiceInterface
{public void ServiceMethod1() { } //空方法public void ServiceMethod2() { } //空方法public void ServiceMethod3() { } //空方法
}
六、雙向適配器模式
- 結構:
- 實現:
public class Adapter : Target, Adaptee
{//同時維持對抽象目標類和適配者的引用private Target target;private Adaptee adaptee;public Adapter(Target target) {this.target = target;}public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}public void Request() {adaptee.SpecificRequest();}public void SpecificRequest() {target.Request();}
}
七、適配器模式的優缺點與適用環境
-
模式適用環境:系統需要使用一些現有的類,而這些類的接口不符合系統的需要,甚至沒有這些類的源代碼
創建一個可以重復使用的類,用于和一些彼此之間沒有太大關聯的類,包括一些可能在將來引進的類一起工作 -
模式優點:
將目標類和適配者類解耦,通過引入一個適配器類來重用現有的適配者類,無須修改原有結構
增加了類的透明性和復用性,提高了適配者的復用性,同一個適配者類可以在多個不同的系統中復用
靈活性和擴展性非常好
類適配器模式:置換一些適配者的方法很方便
對象適配器模式:可以把多個不同的適配者適配到同一個目標,還可以適配一個適配者的子類 -
模式缺點:
類適配器模式:(1) 一次最多只能適配一個適配者類,不能同時適配多個適配者;(2) 適配者類不能為最終類;(3) 目標抽象類只能為接口,不能為類
對象適配器模式:在適配器中置換適配者類的某些方法比較麻煩
經典運用:
Sun公司在1996年公開了Java語言的數據庫連接工具JDBC,JDBC使得Java語言程序能夠與數據庫連接,并使用SQL語言來查詢和操作數據。JDBC給出一個客戶端通用的抽象接口,每一個具體數據庫引擎(如SQL Server、Oracle、MySQL等)的JDBC驅動軟件都是一個介于JDBC接口和數據庫引擎接口之間的適配器軟件。抽象的JDBC接口和各個數據庫引擎API之間都需要相應的適配器軟件,這就是為各個不同數據庫引擎準備的驅動程序。
部分內容由AI大模型生成,請注意識別!