大體介紹
適配器模式(Adapter Pattern)是一種結構型設計模式,其核心目的是通過提供一個適配器類來使得原本接口不兼容的類可以一起工作。它通過將一個類的接口轉換成客戶端所期望的接口,使得原本因接口不兼容而無法一起工作的類可以協同工作。
適配器模式的定義
適配器模式是一種結構型設計模式,允許將一個類的接口轉換成客戶希望的另一個接口,從而解決由于接口不兼容而導致的類無法協同工作的難題。
適配器模式的組成部分
- 目標接口(Target):客戶端所期望的接口,可以是現有的接口,也可以是新定義的接口。
- 源接口(Adaptee):需要適配的現有接口,它和目標接口不兼容。
- 適配器(Adapter):負責將源接口轉化為目標接口的類,它實現目標接口,并且在方法內部調用源接口的實現,從而使得客戶端可以使用目標接口與源接口進行交互。
適配器模式的工作流程
- 客戶端調用目標接口的相關方法,而目標接口的實現由適配器來提供。
- 適配器將客戶端的請求轉化成源接口可以理解的請求,完成適配過程。
- 通過適配器,客戶端無需改變代碼,只需通過適配器與源接口協作即可。
適配器模式的類型
- 類適配器(Class Adapter):通過繼承的方式實現目標接口和源接口的適配。適配器類繼承了源接口的實現類,并實現目標接口。
- 對象適配器(Object Adapter):通過組合的方式實現目標接口和源接口的適配。適配器類包含源接口的實例,并通過代理調用源接口的方法來適配目標接口。
適配器模式的優缺點
優點:
- 可以增加類的透明性:客戶端可以通過目標接口與類交互,而無需了解適配器的存在,適配器隱藏了源接口的復雜性。
- 增強系統的可擴展性:可以通過適配器模式對現有的類進行改造,使其具備新功能,而不需要修改源代碼。
- 支持多個不同的接口:適配器可以將多個不同的接口適配到一個目標接口,提升系統的靈活性。
缺點:
- 增加代碼復雜性:每個源接口都需要一個適配器類,這可能會導致系統中出現大量的適配器類,增加代碼復雜性。
- 可能會影響性能:每次調用方法時都需要通過適配器進行轉發,可能會對系統性能產生一定的影響。
適配器模式的應用場景
適配器模式非常適用于以下幾種場景:
- 需要使用現有類,但其接口不符合需求時:通過適配器將源類的接口轉化為目標接口。
- 希望類可以和不兼容的接口一起工作時:可以通過適配器模式將不兼容的接口適配成兼容接口,避免直接修改類的代碼。
- 在復用已有的類庫時:有時第三方庫的接口可能與現有系統接口不兼容,可以通過適配器模式使其兼容。
- 希望系統中的多個接口能夠統一時:可以通過適配器模式將多個接口統一為一個目標接口,簡化系統的調用。
適配器模式的例子
- MediaPlayer:目標接口,客戶端通過它來播放不同類型的媒體(MP3,MP4,VLC)。
- AudioPlayer:適配者類,負責播放音頻,在加入適配器之前只能播放MP3。
- MP4Player 和 VLCPlayer:高級接口,分別支持播放 MP4 格式和 VLC 格式的媒體。
- MediaAdapter:適配器類,負責將不兼容的接口(如
MP4Player
和VLCPlayer
)適配到MediaPlayer
接口。
接下來,我們將逐步詳細解析這個例子。
// 目標接口:MediaPlayer
interface MediaPlayer {void play(String audioType, String fileName);
}// 具體類:AudioPlayer
class AudioPlayer implements MediaPlayer {MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {// 播放MP3文件if(audioType.equalsIgnoreCase("mp3")){System.out.println("Playing mp3 file. Name: " + fileName);}// 對于其他文件類型,通過適配器來處理else if(audioType.equalsIgnoreCase("mp4") || audioType.equalsIgnoreCase("vlc")){mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);}else {System.out.println("Invalid media. " + audioType + " format not supported");}}
}// 原接口:AdvancedMediaPlayer
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}// 具體類:VlcPlayer(實現AdvancedMediaPlayer)
class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {System.out.println("Playing vlc file. Name: " + fileName);}@Overridepublic void playMp4(String fileName) {// 無法播放 MP4 文件}
}// 具體類:Mp4Player(實現AdvancedMediaPlayer)
class Mp4Player implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {// 無法播放 VLC 文件}@Overridepublic void playMp4(String fileName) {System.out.println("Playing mp4 file. Name: " + fileName);}
}// 適配器類:MediaAdapter
class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType){if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();}else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer.playVlc(fileName);}else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer.playMp4(fileName);}}
}// 客戶端代碼:AdapterPatternDemo
public class AdapterPatternDemo {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");}
}
代碼結構分析
-
目標接口:
MediaPlayer
- 這是客戶端所期望的接口,用于播放不同類型的媒體。客戶端只通過這個接口來播放音頻,不需要關心具體播放的是 MP3、MP4 還是 VLC 格式的文件。
interface MediaPlayer {void play(String audioType, String fileName); }
-
具體類:
AudioPlayer
AudioPlayer
是實現了MediaPlayer
接口的類,支持播放 MP3 格式的音頻文件。- 對于 MP4 和 VLC 格式的音頻,
AudioPlayer
無法直接播放。于是它會通過MediaAdapter
來適配這些格式。
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("mp4") || audioType.equalsIgnoreCase("vlc")){mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);}else {System.out.println("Invalid media. " + audioType + " format not supported");}} }
這里,
AudioPlayer
通過判斷音頻格式來決定是否使用適配器。它直接播放 MP3 文件,對于 MP4 和 VLC 文件則通過MediaAdapter
進行適配。 -
原接口:
AdvancedMediaPlayer
AdvancedMediaPlayer
是一個原接口,定義了播放 MP4 和 VLC 格式文件的方法。- 它有兩個實現類:
VlcPlayer
和Mp4Player
。這些類分別負責播放各自支持的格式,但它們的接口與MediaPlayer
不兼容。
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName); }
VlcPlayer
負責播放.vlc
文件,Mp4Player
負責播放.mp4
文件。兩個類的接口都與MediaPlayer
不兼容,因此我們需要適配器來實現兼容。 -
適配器類:
MediaAdapter
MediaAdapter
是核心的適配器類,它將不兼容的接口(AdvancedMediaPlayer
)轉換為客戶端需要的接口(MediaPlayer
)。- 它實現了
MediaPlayer
接口,并根據需要調用VlcPlayer
或Mp4Player
的相應方法。
class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();} else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {advancedMusicPlayer.play(fileName); // 直接調用通用的 play 方法}
}
MediaAdapter
根據傳入的音頻類型(vlc
或mp4
)創建相應的AdvancedMediaPlayer
對象。- 然后它會調用
VlcPlayer
或Mp4Player
的playVlc()
或playMp4()
方法,完成對 VLC 或 MP4 文件的播放。
-
客戶端代碼:
AdapterPatternDemo
- 客戶端通過
AudioPlayer
來播放各種格式的音頻文件。即使客戶端只知道MediaPlayer
接口,它依然可以播放 MP3、MP4 和 VLC 文件,因為AudioPlayer
通過MediaAdapter
實現了適配功能。
public class AdapterPatternDemo {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");} }
- 客戶端通過
運行結果
Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported
詳細解釋
-
目標接口
MediaPlayer
:定義了play
方法,所有的播放器類(AudioPlayer
和適配器)都實現了這個接口。 -
AudioPlayer
類:實現了MediaPlayer
接口,直接支持播放 MP3 文件。對于其他格式(mp4
和vlc
),它創建MediaAdapter
來適配這兩種格式并播放相應的文件。 -
MediaAdapter
類:適配器的核心作用是將VlcPlayer
和Mp4Player
的方法適配到MediaPlayer
接口。MediaAdapter
使得AudioPlayer
可以播放 MP4 和 VLC 格式的文件,盡管AudioPlayer
為什么適配器類也要實現MediaPlayer接口?
在適配器模式(Adapter Pattern)中,適配器類實現目標接口(在這個例子中是 MediaPlayer
接口)是非常關鍵的一步。下面我會詳細解釋為什么適配器類需要實現目標接口,結合本例進一步展開。
適配器模式的基本概念
適配器模式的核心目標是使得兩個接口不兼容的類能夠一起工作。適配器類充當“橋梁”的角色,它通過實現目標接口,將現有的、與目標接口不兼容的類適配成我們需要的接口形式。
目標接口(MediaPlayer
)
在本例中,MediaPlayer
是客戶端期望使用的接口,它提供了一個統一的播放方法 play()
,客戶端通過這個接口來播放音頻,不關心具體的實現細節。
interface MediaPlayer {void play(String audioType, String fileName);
}
原接口(AdvancedMediaPlayer
)
原接口 AdvancedMediaPlayer
提供了播放 MP4 和 VLC 格式文件的接口。這個接口并不與 MediaPlayer
接口兼容,無法直接被客戶端使用。
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}
適配器類(MediaAdapter
)
適配器類的作用是將不兼容的 AdvancedMediaPlayer
類適配為 MediaPlayer
接口。為了使適配器能夠統一提供 MediaPlayer
的 play()
方法,它需要實現 MediaPlayer
接口。
class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();} else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {advancedMusicPlayer.play(fileName); // 調用適配器的 play 方法}
}
為什么適配器需要實現 MediaPlayer
接口
-
統一接口,符合客戶端需求
- 客戶端希望通過
MediaPlayer
接口來播放各種格式的音頻文件。AudioPlayer
類和MediaAdapter
都需要實現MediaPlayer
接口。 AudioPlayer
類直接實現MediaPlayer
接口,處理 MP3 文件。而對于 MP4 和 VLC 格式的音頻文件,AudioPlayer
則委托給MediaAdapter
。- 如果
MediaAdapter
不實現MediaPlayer
接口,客戶端就無法通過統一的接口來播放所有音頻格式,AudioPlayer
也無法直接調用它。
- 客戶端希望通過
-
符合適配器模式的設計原則
- 適配器模式的本質是“將一個接口適配成另一個接口”。適配器類需要實現目標接口(即
MediaPlayer
接口),才能充當橋梁,把不兼容的接口(如AdvancedMediaPlayer
)適配為客戶端需要的接口。 - 客戶端通過目標接口(
MediaPlayer
)與AudioPlayer
和MediaAdapter
交互,客戶端不需要關心背后具體的實現細節(如VlcPlayer
或Mp4Player
)。
- 適配器模式的本質是“將一個接口適配成另一個接口”。適配器類需要實現目標接口(即
-
增強靈活性和可擴展性
- 通過讓
MediaAdapter
實現MediaPlayer
接口,系統的設計更加靈活。當需要添加新的音頻格式支持時,我們只需要創建一個新的播放器(比如AviPlayer
)并讓它實現AdvancedMediaPlayer
接口。然后,只需擴展MediaAdapter
來支持新格式,無需修改客戶端的代碼。 - 適配器的職責是將一個接口轉換為另一個接口。如果
MediaAdapter
沒有實現MediaPlayer
接口,那么AudioPlayer
就無法通過MediaAdapter
播放新格式的文件,從而破壞了代碼的可擴展性。
- 通過讓
-
與客戶端的耦合
- 由于
MediaAdapter
實現了MediaPlayer
接口,客戶端代碼(例如AudioPlayer
)無需關心其背后是如何實現的,只要通過MediaPlayer
接口進行調用即可。客戶端依賴于接口而非實現,這符合面向接口編程的設計思想。 - 如果適配器類不實現
MediaPlayer
接口,客戶端將無法調用它的play()
方法,客戶端就會與AdvancedMediaPlayer
緊密耦合,失去了適配器的意義。
- 由于
總結
適配器類需要實現 MediaPlayer
接口,目的是:
- 統一接口:使得
MediaAdapter
能與AudioPlayer
一樣,通過MediaPlayer
接口來播放音頻文件,客戶端代碼不會因為使用了不同類型的播放器而發生變化。 - 遵循適配器模式的原則:適配器模式的核心是將一個接口轉換成另一個接口,適配器類通過實現目標接口來實現這一轉換。
- 提高靈活性和擴展性:通過實現目標接口,適配器類可以輕松支持新格式,增強系統的可擴展性。
通過這種設計,客戶端的代碼不會受到播放器具體實現的影響,保持了系統的解耦,也為未來的擴展提供了便利。
若有新的媒體格式播放需求,該如何修改該適配器?
如果有新的媒體格式播放需求(比如新增 .avi
格式支持),你可以按照以下步驟修改適配器模式中的代碼來支持新的格式。我們將以 .avi
格式為例,來展示如何修改適配器和相關代碼。
1. 修改 AdvancedMediaPlayer
接口
首先,在 AdvancedMediaPlayer
接口中增加一個新的方法 playAvi
,用于播放 .avi
格式的文件。
// 原有的接口
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);// 新增支持的 .avi 格式void playAvi(String fileName);
}
2. 新增實現類 AviPlayer
接下來,為 .avi
格式創建一個新的播放器實現類 AviPlayer
,實現 AdvancedMediaPlayer
接口,并實現 playAvi
方法。
class AviPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {// 不支持 VLC 格式}@Overridepublic void playMp4(String fileName) {// 不支持 MP4 格式}@Overridepublic void playAvi(String fileName) {System.out.println("Playing AVI file: " + fileName);}
}
3. 修改 MediaAdapter
類
為了支持 .avi
格式,你需要修改 MediaAdapter
類,增加對 .avi
格式的適配處理。我們可以通過在 MediaAdapter
構造函數中判斷傳入的格式,并創建對應的播放器對象。
class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer = new VlcPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer = new Mp4Player();} else if (audioType.equalsIgnoreCase("avi")) {advancedMusicPlayer = new AviPlayer(); // 新增對 .avi 格式的支持}}@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer.playMp4(fileName);} else if (audioType.equalsIgnoreCase("avi")) {advancedMusicPlayer.playAvi(fileName); // 調用新實現的 playAvi 方法}}
}
4. 修改 AudioPlayerClient
類
最后,在 AudioPlayerClient
中,你需要確保 .avi
格式的播放器被正確使用。當你通過 MediaAdapter
類來適配 .avi
格式時,你可以直接使用它播放 .avi
文件。
class AudioPlayerClient {MediaPlayer audioPlayer;public AudioPlayerClient(MediaPlayer audioPlayer) {this.audioPlayer = audioPlayer;}public void playMedia(String audioType, String fileName) {audioPlayer.play(audioType, fileName);}
}
5. 客戶端調用
現在,客戶端可以通過 MediaAdapter
來支持播放 .avi
格式的音頻文件了。你只需將 .avi
格式的請求傳遞給 AudioPlayerClient
,MediaAdapter
會根據格式自動選擇正確的播放器。
public class Main {public static void main(String[] args) {AudioPlayerClient audioPlayerClient = new AudioPlayerClient(new AudioPlayer());// 測試 MP3 格式audioPlayerClient.playMedia("mp3", "beyond the horizon.mp3");// 測試 VLC 格式audioPlayerClient.playMedia("vlc", "far far away.vlc");// 測試 AVI 格式audioPlayerClient.playMedia("avi", "mind me.avi"); // 新增的 AVI 格式}
}
代碼總結
- 修改接口:在
AdvancedMediaPlayer
接口中新增對.avi
格式播放的支持(即增加playAvi
方法)。 - 新增實現類:為
.avi
格式創建一個新的播放器類AviPlayer
,并實現播放邏輯。 - 修改適配器:在
MediaAdapter
中增加對.avi
格式的支持,在play
方法中進行格式判斷,并調用AviPlayer
的playAvi
方法。 - 客戶端調用:客戶端不需要關心具體實現,只需調用
MediaAdapter
來處理不同的音頻格式。
優勢
- 擴展性強:當你需要支持新的音頻格式時,只需添加一個新的實現類并修改適配器類,而不需要修改現有的客戶端代碼或其他播放器類。
- 符合開閉原則:現有的代碼對修改是封閉的,對擴展是開放的。你只需擴展系統,而不需要修改現有的功能。
- 職責分離清晰:每個播放器類只負責一個格式的播放,適配器類負責將客戶端請求轉發到正確的播放器類,代碼結構更加清晰。
這樣,如果以后還需要增加新的格式,只需要按照這種方式新增相關的播放器實現和適配邏輯,而不需要對現有代碼進行過多修改,確保系統能夠靈活擴展。
面向接口的編程與適配器設計模式
面向接口的編程(Interface-based Programming)和適配器模式(Adapter Pattern)都與接口有很大的關系,它們的設計理念和應用場景有所不同。我們可以通過以下幾個方面來對比這兩者:
1. 基本概念
面向接口的編程:
面向接口的編程是一種設計方法,它強調通過接口來抽象對象的行為,定義不同對象可以遵循的規則或契約。接口只定義行為,不關心具體的實現。
- 目標: 實現靈活、解耦和可擴展的設計,減少模塊之間的耦合度。
- 特點: 類之間通過接口進行交互,具體的實現可以替換而不影響其他部分的代碼。
適配器模式:
適配器模式是一種結構型設計模式,它的目的是將一個類的接口轉換成客戶期望的另一個接口。適配器模式通過引入適配器類來“適配”現有的接口,使得原本由于接口不兼容而無法一起工作的類可以一起工作。
- 目標: 通過一個適配器類,處理接口不兼容的問題,讓不同的接口能夠共同工作。
- 特點: 適配器類在原有接口和目標接口之間進行轉換。
2. 結構差異
面向接口的編程:
- 接口定義: 在面向接口的編程中,我們定義多個接口,多個類可以實現不同的接口。
- 接口實現: 類根據需要實現接口中的方法。不同的實現類提供不同的行為,而客戶端代碼只依賴于接口,而不關心具體的實現。
// 面向接口的編程:定義接口并實現
interface MediaPlayer {void play(String audioType, String fileName);
}class AudioPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("mp3")){System.out.println("Playing mp3 file. Name: " + fileName);}}
}
適配器模式:
- 目標接口和適配接口: 適配器模式涉及兩個接口:目標接口(客戶端期望的接口)和 適配接口(被適配的接口)。適配器類將被適配的接口轉化為目標接口,確保客戶端可以以一致的方式調用。
- 適配器實現: 適配器類實現目標接口,并將客戶端請求轉換為被適配接口的方法調用。
// 適配器模式:適配器將不同格式的播放器統一適配為目標接口 MediaPlayer
interface MediaPlayer {void play(String audioType, String fileName);
}interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {System.out.println("Playing vlc file. Name: " + fileName);}@Overridepublic void playMp4(String fileName) {// Do nothing}
}class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();}}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer.playVlc(fileName);}}
}
3. 核心目的和適用場景
面向接口的編程:
- 目的: 提供高內聚、低耦合的設計。通過接口定義一組行為規范,允許不同的實現類提供具體的實現。接口的抽象為系統的擴展提供了靈活性。
- 適用場景:
- 你需要一個類的多個實現,并且希望能夠在運行時根據需要切換實現。
- 你希望實現代碼復用和解耦,使得類和類之間的依賴最小化。
- 比如,多個類實現一個通用的
MediaPlayer
接口,處理不同格式的音頻播放。
適配器模式:
- 目的: 解決接口不兼容的問題。通過引入適配器類來將不兼容的接口轉換為目標接口,使得原本不能協同工作的類能夠一起工作。
- 適用場景:
- 你有一個現有的類(比如第三方庫提供的類),它有一個不符合你當前系統設計的接口,但你無法更改這個類。
- 你希望將現有的類與新的接口或者類集成,且不想修改現有的類代碼。
- 比如,你需要通過適配器將舊的
.mp3
播放器與新接口集成。
4. 代碼復用 vs. 代碼橋接
面向接口的編程:
- 代碼復用: 面向接口的編程通過接口和抽象類為不同的實現提供復用機會。不同類的實現可以根據需求復用相同的接口。
- 舉例:
AudioPlayer
類可以復用MediaPlayer
接口并實現多種格式的播放,如.mp3
、.mp4
。
適配器模式:
- 代碼橋接: 適配器模式并不要求重寫所有的實現類,而是通過創建適配器類,來在兩個不同接口間建立橋梁。適配器類實現目標接口并委托給被適配類來執行實際的工作。
- 舉例:
MediaAdapter
類作為適配器,橋接了MediaPlayer
接口和AdvancedMediaPlayer
接口之間的差異,將.vlc
播放的請求委托給VlcPlayer
類的playVlc
方法。
5. 靈活性與擴展性
面向接口的編程:
- 靈活性: 高度依賴接口定義,使得代碼能夠更容易被擴展和替換。客戶端與接口解耦,允許替換不同的實現類。
- 擴展性: 新的實現類可以根據需要隨時添加,不影響已有代碼,只要新的實現類遵循相同的接口。
適配器模式:
- 靈活性: 在不修改現有代碼的前提下,能夠使現有類與新接口兼容。適配器模式提供了兼容性,即使原始接口和目標接口之間不兼容,也能通過適配器來解決。
- 擴展性: 如果需要支持新的格式,適配器模式允許你添加新的適配器類,而不需要修改現有的代碼。
6. 代碼實例對比
面向接口編程示例:
interface MediaPlayer {void play(String audioType, String fileName);
}class AudioPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("mp3")){System.out.println("Playing mp3 file. Name: " + fileName);}}
}
適配器模式示例:
interface MediaPlayer {void play(String audioType, String fileName);
}interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {System.out.println("Playing vlc file. Name: " + fileName);}@Overridepublic void playMp4(String fileName) {}
}class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();}}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer.playVlc(fileName);}}
}
7. 總結
特性 | 面向接口的編程 | 適配器模式 |
---|---|---|
核心目標 | 提高靈活性和解耦,通過接口實現行為抽象 | 通過適配器將不兼容的接口轉為目標接口 |
主要目的 | 實現代碼的可擴展性和可替換性 | 解決接口不兼容的問題 |
應用場景 | 需要多種類實現相同接口時 | 需要集成不同接口(特別是現有接口)時 |
設計特點 | 定義統一的接口,多個類實現 | 使用適配器類將不同接口橋接為一個統一接口 |