大话设计模式—适配器模式
適配器模式(Adapter Pattern)是作為兩個不兼容的接口之間的橋梁。這種類型的設計模式屬于結構型模式,它結合了兩個獨立接口的功能。這種模式涉及到一個單一的類,該類負責加入獨立的或不兼容的接口功能。舉個真實的例子,讀卡器是作為內存卡和筆記本之間的適配器。您將內存卡插入讀卡器,再將讀卡器插入筆記本,這樣就可以通過筆記本來讀取內存卡。主要解決在軟件系統中,常常要將一些”現存的對象”放到新的環境中,而新環境要求的接口是現對象不能滿足的。
大話設計模式中程杰老師給出的定義是,適配器模式:將一個類的接口轉換成客戶希望的另外一個接口。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
系統數據和行為都正確,但接口不符合時,我們應該考慮用適配器,目的是使控制范圍之外的一個原有對象與某個接口匹配。
在GoF的設計模式中,對適配器講了兩種類型,類適配器模式和對象適配器模式,由于類適配器模式通過多重繼承對一個接口與另一個接口進行匹配,而C#、VB.NET、JAVA等語言都不支持多重繼承(C++支持),也就是一個類只有一個父類,所以這里我們只涉及對象適配器。
適配器模式結構圖:
實例解析:
我們有一個 MediaPlayer 接口和一個實現了 MediaPlayer 接口的實體類 AudioPlayer。默認情況下,AudioPlayer 可以播放 mp3 格式的音頻文件。我們還有另一個接口 AdvancedMediaPlayer 和實現了 AdvancedMediaPlayer 接口的實體類。該類可以播放 vlc 和 mp4 格式的文件。我們想要讓 AudioPlayer 播放其他格式的音頻文件。為了實現這個功能,我們需要創建一個實現了 MediaPlayer 接口的適配器類MediaAdapter,并使用 AdvancedMediaPlayer 對象來播放所需的格式。AudioPlayer 使用適配器類 MediaAdapter 傳遞所需的音頻類型,不需要知道能播放所需格式音頻的實際類。AdapterPatternDemo,我們的演示類使用 AudioPlayer 類來播放各種格式。
package com.exercise.adapter; /*** 為媒體播放器創建接口* @author lmb**/ public interface MediaPlayer {public void play(String audioType,String fileName); } package com.exercise.adapter; /*** 為高級的媒體播放器創建接口* @author lmb**/ public interface AdvancedMediaPlayer {public void playMp4(String fileName);public void playVlc(String fileName); } package com.exercise.adapter; /*** 高級媒體播放器接口的實現類Mp4Player* @author lmb**/ public class Mp4Player implements AdvancedMediaPlayer {@Overridepublic void playMp4(String fileName) {// 播放MP4格式的媒體System.out.println("playing mp4 fileName : " + fileName);}@Overridepublic void playVlc(String fileName) {// do nothing}} package com.exercise.adapter; /*** 高級媒體播放器接口的實現類VlcPlayer* @author lmb**/ public class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playMp4(String fileName) {//do nothing}@Overridepublic void playVlc(String fileName) {// 播放Vlc格式的媒體System.out.println("playing vlc fileName : " + fileName);}} package com.exercise.adapter; /*** 創建實現MediaPlayer接口的適配器類MediaAdapter* @author lmb**/ public class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMediaPlayer;//constructorpublic 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);}}} package com.exercise.adapter; /*** 創建MediaPlayer接口的實體類* @author lmb**/ public class AudioPlayer implements MediaPlayer {MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("mp3")) {// 內置支持mp3格式的媒體System.out.println("play mp3 fileName : " + 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");}}} package com.exercise.adapter;public class AdapterTestDemo {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "love.mp3");audioPlayer.play("mp4", "love.mp4");audioPlayer.play("vlc", "love.vlc");audioPlayer.play("bhd", "love.bhd");}}運行結果:
使用場景:
1、在想使用一個已經存在的類,但如果它的接口也就是它的方法和你的要求不相同時,就應該考慮適配器模式。即有動機地修改一個正常運行的系統的接口時。
2、在設計之初就考慮適配器模式:比如公司設計一個系統時考慮使用第三方開發組件,而這個組件的接口與我們自己的系統接口是不相同的,而我們也完全沒有必要為了迎合它而改動自己的接口,此時盡管在開發的設計階段,也是可以考慮用適配器模式來解決接口不同的問題。
適配器模式在.NET中的應用
在.NET中有一個類庫已經實現的、非常重要的適配器,那就是DataAdapter。DataAdapter用作DataSet和數據源之間的適配器以便檢索和保存數據。DataAdapter通過映射Fill(這更改了DataSet中的數據以便于數據源中的數據項匹配)和Update(這更改了數據源中的數據以便于DataSet中的數據項匹配)來提供這一適配器。由于數據源可能來自SQL Server或者oracle或者Access、DB2,這些數據在組織上可能有不同之處,但我們希望得到統一的DataSet(實質是XML數據),此時用DataAdapter就是非常好的手段,我們不必關注不同數據庫的數據細節,就可以靈活的使用數據。
優點:
1、可以讓任何兩個沒有關聯的類一起運行。
2、提高了類的復用。
3、增加了類的透明度。
4、靈活性好。
缺點:
1、過多地使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是 A 接口,其實內部被適配成了 B 接口的實現,一個系統如果太多出現這種情況,無異于一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
2.由于 JAVA 至多繼承一個類,所以至多只能適配一個適配者類,而且目標類必須是抽象類。
注意事項:適配器不是在詳細設計時添加的,而是解決正在服役的項目的問題。
總結
以上是生活随笔為你收集整理的大话设计模式—适配器模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大话设计模式—状态模式
- 下一篇: 【定时任务】quartz表达式Cron