当前位置: 首页 > article >正文

适配器模式概述

大体介绍

适配器模式(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;

    @Override
    public 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 {

    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // 无法播放 MP4 文件
    }
}

// 具体类:Mp4Player(实现AdvancedMediaPlayer)
class Mp4Player implements AdvancedMediaPlayer {

    @Override
    public void playVlc(String fileName) {
        // 无法播放 VLC 文件
    }

    @Override
    public 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();
        }
    }

    @Override
    public 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;
    
        @Override
        public 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();
        }
    }

    @Override
    public 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();
        }
    }

    @Override
    public 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 {
    @Override
    public void playVlc(String fileName) {
        // 不支持 VLC 格式
    }

    @Override
    public void playMp4(String fileName) {
        // 不支持 MP4 格式
    }

    @Override
    public 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 格式的支持
        }
    }

    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // Do nothing
    }
}

class MediaAdapter implements MediaPlayer {
    AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        if(audioType.equalsIgnoreCase("vlc")){
            advancedMusicPlayer = new VlcPlayer();
        }
    }

    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {}
}

class MediaAdapter implements MediaPlayer {
    AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        if(audioType.equalsIgnoreCase("vlc")){
            advancedMusicPlayer = new VlcPlayer();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if(audioType.equalsIgnoreCase("vlc")){
            advancedMusicPlayer.playVlc(fileName);
        }
    }
}

7. 总结

特性面向接口的编程适配器模式
核心目标提高灵活性和解耦,通过接口实现行为抽象通过适配器将不兼容的接口转为目标接口
主要目的实现代码的可扩展性和可替换性解决接口不兼容的问题
应用场景需要多种类实现相同接口时需要集成不同接口(特别是现有接口)时
设计特点定义统一的接口,多个类实现使用适配器类将不同接口桥接为一个统一接口

http://www.kler.cn/a/455759.html

相关文章:

  • 41 stack类与queue类
  • 【SpringMVC】Bean 加载控制
  • linux ext4文件系统
  • 单片机与MQTT协议
  • 畅游 Linux 开发天地:yum 与 vim 详解
  • C程序设计:数据在数组中的交换
  • 【华为OD-E卷-AI处理器组合100分(python、java、c++、js、c)】
  • IDEA | SpringBoot 项目中使用 Apifox 上传接口
  • linux自动化一键批量检查主机端口
  • Ruby 数据库访问 - DBI 教程
  • 内网DNS解析 (PrivateZone)
  • 洪水灾害多智能体分布式模拟示例代码
  • 大数据存储ZNS,缘起与进化:Open-Channel SSD到ZNS的发展
  • mysql-二进制安装方式
  • 平安夜与圣诞节,如何玩转节日选题?
  • 20241227解决使用向日葵远程工具连接ubuntu20.04.5出现黑屏的问题
  • 两个控制器NTP/ptp时间同步
  • UE(虚幻)学习(四) 第一个C++类来控制小球移动来理解蓝图和脚本如何工作
  • 使用Python实现智慧城市数据平台:走向未来的智能城市管理
  • 如何使用Python和PIL库生成带竖排文字的封面图像
  • IS-IS(Intermediate System to Intermediate System)
  • Peter Lax线性代数教材:Linear Algebra and Its Applications 2nd Ed
  • vue3项目使用scss报错相关处理
  • 使用Vue+Django开发的旅游路书应用
  • 专业版pycharm与服务器连接
  • HarmonyOS Next 应用元服务开发-应用接续动态配置迁移按需退出