一、引言 最近懶勁又上來了,隔了幾天沒有學習,最近的博文閱讀量也比較少,不過還是希望自己堅持下去,相信水滴石穿,量變總會引起質變的。 今天要學習的是適配器模式,顧名思義,適配器模式是將兩個不相容的介面進行適配,類似轉換器的功能。 先看一個例子,我們一個播放器,它有一個播放功能(繼承一個播放介面,只有 ...
一、引言
最近懶勁又上來了,隔了幾天沒有學習,最近的博文閱讀量也比較少,不過還是希望自己堅持下去,相信水滴石穿,量變總會引起質變的。
今天要學習的是適配器模式,顧名思義,適配器模式是將兩個不相容的介面進行適配,類似轉換器的功能。
先看一個例子,我們一個播放器,它有一個播放功能(繼承一個播放介面,只有一個播放方法),最開始的時候它只支持播放MP3功能,現隨著播放源的增多,我們想讓它支持播放更多的文件類型。有一個廠商提供了其他的播放介面,但是其中的方法並不是叫做播放方法,這個時候我們必須把新廠商的介面轉換成開始繼承的播放介面,也就是把現在廠商的介面偽裝成最先繼承的播放介面,讓它能夠適配原先的方法
實際目的是讓將一個介面轉換成客戶想要的另一個介面,適配器模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。
二、適配器模式
定義:適配器模式把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠在一起工作。
意圖:將一個類的介面轉換成客戶希望的另外一個介面。適配器模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。
主要解決:主要解決在軟體系統中,常常要將一些"現存的對象"放到新的環境中,而新環境要求的介面是現對象不能滿足的。
何時使用: 1、系統需要使用現有的類,而此類的介面不符合系統的需要。 2、想要建立一個可以重覆使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作,這些源類不一定有一致的介面。 3、通過介面轉換,將一個類插入另一個類系中。(比如老虎和飛禽,現在多了一個飛虎,在不增加實體的需求下,增加一個適配器,在裡面包容一個虎對象,實現飛的介面。)
如何解決:繼承或依賴
類圖:
三、代碼實現
//原先的播放器介面 public interface MediaPlayer { void play(String audioType, String fileName); } //新的高級播放器介面 public interface AdvancedMediaPlayer { void playVlc(String fileName); void playMp4(String fileName); } //繼承高級播放介面的MP4播放器 public class Mp4Player implements AdvancedMediaPlayer { @Override public void playVlc(String fileName) { } @Override public void playMp4(String fileName) { System.out.println("Playing mp4 file. Name: "+ fileName); } } //繼承高級播放介面的VlC播放器 public class VlcPlayer implements AdvancedMediaPlayer { @Override public void playVlc(String fileName) { System.out.println("Playing vlc file. Name: "+ fileName); } @Override public void playMp4(String fileName) { } } //適配器類 public class MediaAdapter implements MediaPlayer { MediaAdapter mediaAdapter; AdvancedMediaPlayer advancedMediaPlayer; public MediaAdapter(String audioType){ if(audioType.equalsIgnoreCase("vlc")){ advancedMediaPlayer=new VlcPlayer(); }else{ advancedMediaPlayer=new Mp4Player(); } } @Override //將現在的介面方法轉換成原先介面的方法 public void play(String audioType, String fileName) { if(audioType.equalsIgnoreCase("vlc")){ advancedMediaPlayer.playVlc(fileName); }else{ advancedMediaPlayer.playMp4(fileName); } } } //播放器 public class AudioPlayer implements MediaPlayer { MediaAdapter mediaAdapter; @Override public void play(String audioType, String fileName) { //播放 mp3 音樂文件的內置支持 if(audioType.equalsIgnoreCase("mp3")){ System.out.println("Playing mp3 file. Name: "+ fileName); } //mediaAdapter 提供了播放其他文件格式的支持 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"); } } } //實現 private static void adapter() { 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"); }
結果:
四、總結
優點: 1、可以讓任何兩個沒有關聯的類一起運行。 2、提高了類的復用。 3、增加了類的透明度。 4、靈活性好。
缺點: 1、過多地使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是 A 介面,其實內部被適配成了 B 介面的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。 2.由於 JAVA 至多繼承一個類,所以至多只能適配一個適配者類,而且目標類必須是抽象類。
使用場景:有動機地修改一個正常運行的系統的介面,這時應該考慮使用適配器模式。
註意事項:適配器不是在詳細設計時添加的,而是解決正在服役的項目的問題。
源代碼地址:https://gitee.com/yuanqinnan/pattern