適配器模式
適配器模式是一種結構型設計模式,其主要作用是解決兩個不兼容接口之間的兼容性問題。適配器模式通過引入一個適配器來將一個類的接口轉換成客戶端所期望的另一個接口,從而讓原本由于接口不匹配而無法協同工作的類能夠協同工作。
結構
適配器模式(Adapter)包含以下主要角色:
- 目標(Target)接口:當前系統業務所期待的接口,它可以是抽象類或接口。
- 適配者(Adaptee)類:它是被訪問和適配的現存組件庫中的組件接口。
- 適配器(Adapter)類:它是一個轉換器,通過繼承或引用適配者的對象,把適配者接口轉換成目標接口,讓客戶按目標接口的格式訪問適配者。
圖例:
AudioPlayer實現了 MediaPlayer 接口,只可以播放 mp3 。實現了 AdvancedMediaPlayer 接口的類則可以播放 vlc 和 mp4 格式的文件。可以創建一個實現了 MediaPlayer 接口的適配器類 MediaAdapter,并使用 AdvancedMediaPlayer 的實現類對象來播放所需的格式。AdapterPatternDemo 類則可以使用 AudioPlayer 類來播放各種格式的音頻。
對象適配器模式代碼案例:
// 目標接口
interface MediaPlayer {void play(String audioType, String filename);
}// 適配器接口
interface AdvancedMediaPlayer {void playVlc(String filename);void playMp4(String filename);
}// 適配器類
class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMediaPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMediaPlayer = new VlcPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMediaPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String filename) {if (audioType.equalsIgnoreCase("vlc")) {advancedMediaPlayer.playVlc(filename);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMediaPlayer.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");}}
}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 Mp4Player implements AdvancedMediaPlayer {@Overridepublic void playVlc(String filename) {// Do nothing}@Overridepublic void playMp4(String filename) {System.out.println("Playing mp4 file. Name: " + filename);}
}// 使用示例
public class Main {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "song.mp3");audioPlayer.play("vlc", "movie.vlc");audioPlayer.play("mp4", "video.mp4");}
}
適配器模式有類適配器模式和對象適配器模式;這里使用對象適配器模式主要是類適配器模式違背了合成復用原則,它限制了適配器類只能適配一個具體的被適配者類。且Java 不支持多重繼承,因此在 Java 中一般使用接口來實現類似的功能
比如下面類適配器,采用的是繼承:
// 適配器類(類適配器)
class MediaAdapter extends Mp4Player implements MediaPlayer { @Overridepublic void play(String audioType, String filename) {if (audioType.equalsIgnoreCase("vlc")) {playVlc(filename);} else if (audioType.equalsIgnoreCase("mp4")) {playMp4(filename);}}
}
當然,也有接口適配器模式,不過使用相對較少。當一個接口擁有許多方法,但實現類只需要實現其中一部分方法時,可以使用接口適配器模式,提供一個抽象適配器類實現該接口,并提供默認實現,從而避免實現類需要實現大量空方法。
使用場景:
- 當需要使用一個已經存在的類,但是它的接口不符合當前需求時,可以考慮使用適配器模式。
- 當需要復用一些已經存在的類,但是接口與其他類不兼容時,可以考慮使用適配器模式。
- 當需要創建一個可復用的類,該類可以與不相關或不可預見的類協同工作時,可以考慮使用適配器模式。