適配器模式概述

大體介紹

適配器模式(Adapter Pattern)是一種結構型設計模式,其核心目的是通過提供一個適配器類來使得原本接口不兼容的類可以一起工作。它通過將一個類的接口轉換成客戶端所期望的接口,使得原本因接口不兼容而無法一起工作的類可以協同工作。

適配器模式的定義

適配器模式是一種結構型設計模式,允許將一個類的接口轉換成客戶希望的另一個接口,從而解決由于接口不兼容而導致的類無法協同工作的難題。

適配器模式的組成部分

  1. 目標接口(Target):客戶端所期望的接口,可以是現有的接口,也可以是新定義的接口。
  2. 源接口(Adaptee):需要適配的現有接口,它和目標接口不兼容。
  3. 適配器(Adapter):負責將源接口轉化為目標接口的類,它實現目標接口,并且在方法內部調用源接口的實現,從而使得客戶端可以使用目標接口與源接口進行交互。

適配器模式的工作流程

  • 客戶端調用目標接口的相關方法,而目標接口的實現由適配器來提供。
  • 適配器將客戶端的請求轉化成源接口可以理解的請求,完成適配過程。
  • 通過適配器,客戶端無需改變代碼,只需通過適配器與源接口協作即可。

適配器模式的類型

  1. 類適配器(Class Adapter):通過繼承的方式實現目標接口和源接口的適配。適配器類繼承了源接口的實現類,并實現目標接口。
  2. 對象適配器(Object Adapter):通過組合的方式實現目標接口和源接口的適配。適配器類包含源接口的實例,并通過代理調用源接口的方法來適配目標接口。

適配器模式的優缺點

優點:
  • 可以增加類的透明性:客戶端可以通過目標接口與類交互,而無需了解適配器的存在,適配器隱藏了源接口的復雜性。
  • 增強系統的可擴展性:可以通過適配器模式對現有的類進行改造,使其具備新功能,而不需要修改源代碼。
  • 支持多個不同的接口:適配器可以將多個不同的接口適配到一個目標接口,提升系統的靈活性。
缺點:
  • 增加代碼復雜性:每個源接口都需要一個適配器類,這可能會導致系統中出現大量的適配器類,增加代碼復雜性。
  • 可能會影響性能:每次調用方法時都需要通過適配器進行轉發,可能會對系統性能產生一定的影響。

適配器模式的應用場景

適配器模式非常適用于以下幾種場景:

  1. 需要使用現有類,但其接口不符合需求時:通過適配器將源類的接口轉化為目標接口。
  2. 希望類可以和不兼容的接口一起工作時:可以通過適配器模式將不兼容的接口適配成兼容接口,避免直接修改類的代碼。
  3. 在復用已有的類庫時:有時第三方庫的接口可能與現有系統接口不兼容,可以通過適配器模式使其兼容。
  4. 希望系統中的多個接口能夠統一時:可以通過適配器模式將多個接口統一為一個目標接口,簡化系統的調用。

適配器模式的例子

  1. MediaPlayer:目標接口,客戶端通過它來播放不同類型的媒體(MP3,MP4,VLC)。
  2. AudioPlayer:適配者類,負責播放音頻,在加入適配器之前只能播放MP3。
  3. MP4PlayerVLCPlayer:高級接口,分別支持播放 MP4 格式和 VLC 格式的媒體。
  4. MediaAdapter:適配器類,負責將不兼容的接口(如 MP4PlayerVLCPlayer)適配到 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");}
}

代碼結構分析

  1. 目標接口:MediaPlayer

    • 這是客戶端所期望的接口,用于播放不同類型的媒體。客戶端只通過這個接口來播放音頻,不需要關心具體播放的是 MP3、MP4 還是 VLC 格式的文件。
    interface MediaPlayer {void play(String audioType, String fileName);
    }
    
  2. 具體類: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 進行適配。

  3. 原接口:AdvancedMediaPlayer

    • AdvancedMediaPlayer 是一個原接口,定義了播放 MP4 和 VLC 格式文件的方法。
    • 它有兩個實現類:VlcPlayerMp4Player。這些類分別負責播放各自支持的格式,但它們的接口與 MediaPlayer 不兼容。
    interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
    }
    

    VlcPlayer 負責播放 .vlc 文件,Mp4Player 負責播放 .mp4 文件。兩個類的接口都與 MediaPlayer 不兼容,因此我們需要適配器來實現兼容。

  4. 適配器類:MediaAdapter

    • MediaAdapter 是核心的適配器類,它將不兼容的接口(AdvancedMediaPlayer)轉換為客戶端需要的接口(MediaPlayer)。
    • 它實現了 MediaPlayer 接口,并根據需要調用 VlcPlayerMp4Player 的相應方法。
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 根據傳入的音頻類型(vlcmp4)創建相應的 AdvancedMediaPlayer 對象。
  • 然后它會調用 VlcPlayerMp4PlayerplayVlc()playMp4() 方法,完成對 VLC 或 MP4 文件的播放。
  1. 客戶端代碼: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

詳細解釋

  1. 目標接口 MediaPlayer:定義了 play 方法,所有的播放器類(AudioPlayer 和適配器)都實現了這個接口。

  2. AudioPlayer:實現了 MediaPlayer 接口,直接支持播放 MP3 文件。對于其他格式(mp4vlc),它創建 MediaAdapter 來適配這兩種格式并播放相應的文件。

  3. MediaAdapter:適配器的核心作用是將 VlcPlayerMp4Player 的方法適配到 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 接口。為了使適配器能夠統一提供 MediaPlayerplay() 方法,它需要實現 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 接口

  1. 統一接口,符合客戶端需求

    • 客戶端希望通過 MediaPlayer 接口來播放各種格式的音頻文件。AudioPlayer 類和 MediaAdapter 都需要實現 MediaPlayer 接口。
    • AudioPlayer 類直接實現 MediaPlayer 接口,處理 MP3 文件。而對于 MP4 和 VLC 格式的音頻文件,AudioPlayer 則委托給 MediaAdapter
    • 如果 MediaAdapter 不實現 MediaPlayer 接口,客戶端就無法通過統一的接口來播放所有音頻格式,AudioPlayer 也無法直接調用它。
  2. 符合適配器模式的設計原則

    • 適配器模式的本質是“將一個接口適配成另一個接口”。適配器類需要實現目標接口(即 MediaPlayer 接口),才能充當橋梁,把不兼容的接口(如 AdvancedMediaPlayer)適配為客戶端需要的接口。
    • 客戶端通過目標接口(MediaPlayer)與 AudioPlayerMediaAdapter 交互,客戶端不需要關心背后具體的實現細節(如 VlcPlayerMp4Player)。
  3. 增強靈活性和可擴展性

    • 通過讓 MediaAdapter 實現 MediaPlayer 接口,系統的設計更加靈活。當需要添加新的音頻格式支持時,我們只需要創建一個新的播放器(比如 AviPlayer)并讓它實現 AdvancedMediaPlayer 接口。然后,只需擴展 MediaAdapter 來支持新格式,無需修改客戶端的代碼。
    • 適配器的職責是將一個接口轉換為另一個接口。如果 MediaAdapter 沒有實現 MediaPlayer 接口,那么 AudioPlayer 就無法通過 MediaAdapter 播放新格式的文件,從而破壞了代碼的可擴展性。
  4. 與客戶端的耦合

    • 由于 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 格式的請求傳遞給 AudioPlayerClientMediaAdapter 會根據格式自動選擇正確的播放器。

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 格式}
}

代碼總結

  1. 修改接口:在 AdvancedMediaPlayer 接口中新增對 .avi 格式播放的支持(即增加 playAvi 方法)。
  2. 新增實現類:為 .avi 格式創建一個新的播放器類 AviPlayer,并實現播放邏輯。
  3. 修改適配器:在 MediaAdapter 中增加對 .avi 格式的支持,在 play 方法中進行格式判斷,并調用 AviPlayerplayAvi 方法。
  4. 客戶端調用:客戶端不需要關心具體實現,只需調用 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. 總結

特性面向接口的編程適配器模式
核心目標提高靈活性和解耦,通過接口實現行為抽象通過適配器將不兼容的接口轉為目標接口
主要目的實現代碼的可擴展性和可替換性解決接口不兼容的問題
應用場景需要多種類實現相同接口時需要集成不同接口(特別是現有接口)時
設計特點定義統一的接口,多個類實現使用適配器類將不同接口橋接為一個統一接口

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64579.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64579.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64579.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

計算機專業考研 408 學科學習方法

計算機專業考研 408 學科涵蓋數據結構、計算機組成原理、操作系統和計算機網絡四門核心課程,內容多且難度大。但只要掌握科學的學習方法,便能化繁為簡,穩步提升。以下為大家詳細介紹 408 學科的學習方法。 一、基礎夯實階段:全面…

C++ 設計模式:命令模式(Command Pattern)

鏈接:C 設計模式 鏈接:C 設計模式 - 訪問器模式 命令模式(Command Pattern)是一種行為型設計模式,它將請求封裝成一個對象,從而使你可以用不同的請求對客戶進行參數化,對請求排隊或記錄請求日志…

html+css+js網頁設計 美食 美食4個頁面帶js

htmlcssjs網頁設計 美食 美食4個頁面帶js 網頁作品代碼簡單,可使用任意HTML輯軟件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html編輯軟件進行運行及修改編輯等操作)。 獲取源碼 1&#…

swagger,showdoc,apifox,Mock 服務,dubbo,ZooKeeper和dubbo的關系

Swagger、ShowDoc 和 Apifox 之間的區別與優勢 Swagger、ShowDoc 和 Apifox 都是用于 API 文檔管理和測試的工具,但它們各有特色和適用場景。以下是詳細的比較,并附上每個工具的具體用法示例。 1. Swagger 特點與優勢: 廣泛采用: Swagger…

邊沿檢測電路漏檢原因分析

邊沿檢測電路漏檢原因分析 常用結構如下&#xff1a; module edge_detect1( input clk, input signal, output pe, //上升沿 output ne, //下降沿 output de //雙邊沿 );reg reg1;always(posedge clk) beginreg1 < signal; endassign pe (~reg1) & signal; assign…

嵌入式硬件雜談(七)IGBT MOS管 三極管應用場景與區別

引言&#xff1a;在現代嵌入式硬件設計中&#xff0c;開關元件作為電路中的重要組成部分&#xff0c;起著至關重要的作用。三種主要的開關元件——IGBT&#xff08;絕緣柵雙極型晶體管&#xff09;、MOSFET&#xff08;金屬氧化物半導體場效應晶體管&#xff09;和三極管&#…

鴻蒙開發:了解正則表達式

前言 從給出的文本中&#xff0c;按照既定的相關規則&#xff0c;匹配出符合的數據&#xff0c;其中的規則就是正則表達式&#xff0c;使用正則表達式&#xff0c;可以使得我們用簡潔的代碼就能實現一定復雜的邏輯&#xff0c;比如判斷一個郵箱賬號是否符合正常的郵箱賬號&…

Kafka的acks機制和ISR列表

Kafka 是一個流行的分布式流處理平臺&#xff0c;用于構建實時數據流管道和應用程序。在 Kafka 中&#xff0c;acks 機制和 ISR&#xff08;In-Sync Replicas&#xff09;列表是兩個重要的概念&#xff0c;它們共同確保消息的持久性和可靠性。 acks 機制 acks 機制是 Kafka 生…

在 Ubuntu 下通過 Docker 部署 Caddy 服務器

嘿&#xff0c;伙伴們&#xff01;今天我們來聊聊如何在 Ubuntu 系統下通過 Docker 部署 Caddy 服務器。Caddy 是一個現代的 Web 服務器&#xff0c;支持自動 HTTPS&#xff0c;簡單易用&#xff0c;特別適合快速搭建網站。而 Docker 則是一個讓你可以隔離和管理應用的神器。結…

計算機網絡?自頂向下方法:網絡層介紹、路由器的組成

網絡層介紹 網絡層服務&#xff1a;網絡層為傳輸層提供主機到主機的通信服務 每一臺主機和路由器都運行網絡層協議 發送終端&#xff1a;將傳輸層報文段封裝到網絡層分組中&#xff0c;發送給邊緣路由器路由器&#xff1a;將分組從輸入鏈路轉發到輸出鏈路接收終端&#xff1…

Linux top指令

top指令概述 top 是 Linux 系統中用于實時監控系統性能和進程信息的命令&#xff0c;功能強大且靈活。它提供了系統資源的動態視圖&#xff0c;包括 CPU、內存、運行中的進程等。 這個指令可以說是Linux中最基本的工具了&#xff0c;用來監視系統的實時運行狀態&#xff0c;類…

Qt監控系統放大招/歷經十幾年迭代完善/多屏幕輔屏預覽/多層級設備樹/網絡登錄和回放

一、前言說明 近期對視頻監控系統做了比較大的更新升級&#xff0c;主要就是三點&#xff0c;第一點就是增加了輔屏預覽&#xff0c;這個也是好多個客戶需要的功能&#xff0c;海康的iVMS-4200客戶端就有這個功能&#xff0c;方便在多個屏幕打開不同的視頻進行查看&#xff0c…

網絡原理(六): UDP 協議

目錄 1. UDP 協議 1.1 協議特點 1.2 協議報文格式 1.2.1 UDP 長度 1.2.2 校驗和 1. UDP 協議 在進行網絡編程時, 我們已經對 UDP 協議進行了簡單了解. 并且應用層的很多操作, 需要調用傳輸層的提供的接口, 基于 socket api 來進行完成的. 1.1 協議特點 UDP 協議具有以…

前端頁面展示本電腦的攝像頭,并使用js獲取攝像頭列表

可以通過 JavaScript 使用 navigator.mediaDevices.enumerateDevices() 獲取電腦上的攝像頭列表。以下是一個示例代碼&#xff0c;可以展示攝像頭列表并選擇進行預覽。 HTML JavaScript 實現攝像頭列表展示和預覽 <!DOCTYPE html> <html lang"zh-CN">…

【漫話機器學習系列】028.CP

Mallows’ Cp&#xff1a;標準化公式解析與應用 Mallows’ Cp 是一種常用的模型選擇工具&#xff0c;用于在一系列候選模型中權衡擬合度和復雜性&#xff0c;幫助我們選擇性能最優的模型。本文將基于其標準化公式展開詳細解析&#xff0c;并探討其應用場景、實現方法、優點與局…

期末算法分析程序填空題

目錄 5-1 最小生成樹&#xff08;普里姆算法&#xff09; 5-2 快速排序&#xff08;分治法&#xff09; 輸入樣例&#xff1a; 輸出樣例&#xff1a; 5-3 歸并排序(遞歸法) 輸入樣例&#xff1a; 輸出樣例&#xff1a; 5-4 求解編輯距離問題&#xff08;動態規劃法&#xff09;…

深入解析 Conda 安裝的默認依賴包及其作用:conda create安裝了哪些包(中英雙語)

深入解析 Conda 安裝的默認依賴包及其作用 當我們使用 Conda 創建新環境時&#xff0c;例如執行命令&#xff1a; conda create -n olmes python3.10Conda 會自動為我們安裝一系列基礎依賴包&#xff0c;保證 Python 環境能夠正常運行。這些包不僅是我們開發的基礎工具&#…

Mac、Linux命令

Linux 查本機IP&#xff1a;ip addr 查詢文件里符合條件的字符串&#xff1a;grep Mac 查本機IP&#xff1a;ipconfig

Visual Studio 中增加的AI功能

前言&#xff1a; 人工智能的發展&#xff0c;在現在&#xff0c;編程技術的IDE里面也融合了AI的基本操做。本例&#xff0c;以微軟的Visual Studio中的人工智能的功能介紹例子。 本例的環境&#xff1a; Visual Studio 17.12 1 AI 智能變量檢測&#xff1a; 上圖展示了一…

江科大學習筆記之——HAL庫點亮一個LED燈

HAL三步走&#xff1a;1.建工程。2.設配置。3.寫代碼 一.建立工程 HAL庫寫法 點擊FinIsh 2.配置時鐘 2 、設置配置參數 把模塊.C.h單獨設置文件 生產代碼 三寫代碼 控制GPIO就三步 1.RCC時鐘使能 2.結構體配置GPIO寄存器 3.控制GPIO值 上面的步驟已經把前兩步的配置完成了接下…