设计模式七:适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口。它允许不兼容的接口能够协同工作。

适配器模式涉及角色:

  1. 目标接口(Target Interface):目标接口是客户端所期望的接口,适配器将源接口转换为目标接口以满足客户端的需求。
  2. 适配器(Adapter):适配器是一个实现了目标接口的类,它持有一个源接口的引用。适配器通过调用源接口的方法来完成客户端的请求,并根据需要进行数据转换和适配。
  3. 源接口(Adaptee Interface):源接口是需要被适配的接口,它定义了适配器需要转换成目标接口的方法。。

适配器模式的使用场景

  1. 兼容性问题:当有两个或多个类之间存在兼容性问题,无法直接进行交互时,可以使用适配器模式。适配器将不兼容的接口转换成目标接口,使得这些类能够协同工作
  2. 类库的使用:当需要使用一个已有的类库,但其接口与当前系统的需要不符时,可以使用适配器来适配该类库的接口,以便于在当前系统中使用。
  3. 组件复用:当希望复用已有的组件,并且这些组件的接口与当前系统的需求不一致时,可以使用适配器模式来对这些组件进行适配,以便在当前系统中复用它们。
  4. 系统扩展性:当系统需要扩展以支持新的功能或接口时,可以使用适配器模式。通过适配器,能够方便地添加新的适配器来支持新的功能或接口,而无需修改现有的代码。
    适配器模式提供了一种解决兼容性问题和接口不一致问题的灵活方式,可以有效地将现有的代码与新的需求或组件进行集成。

适配器模式的java代码实例

java 复制代码
// 目标接口
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 具体目标类
class AudioPlayer implements MediaPlayer {
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing mp3 file: " + fileName);
        } else {
            System.out.println("Invalid media type");
        }
    }
}

// 高级媒体播放器接口
interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

// 具体高级媒体播放器类
class VlcPlayer implements AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file: " + fileName);
    }

    public void playMp4(String fileName) {
        // 不支持,不做任何操作
    }
}

class Mp4Player implements AdvancedMediaPlayer {
    public void playVlc(String fileName) {
        // 不支持,不做任何操作
    }

    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file: " + 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();
        }
    }

    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer.playMp4(fileName);
        } else {
            System.out.println("Invalid media type");
        }
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        MediaPlayer mediaPlayer = new AudioPlayer();

        mediaPlayer.play("mp3", "song.mp3"); // 直接播放MP3文件

        mediaPlayer = new MediaAdapter("vlc");
        mediaPlayer.play("vlc", "movie.vlc"); // 使用适配器播放VLC文件

        mediaPlayer = new MediaAdapter("mp4");
        mediaPlayer.play("mp4", "video.mp4"); // 使用适配器播放MP4文件
    }
}

在上面的示例中,MediaPlayer 是目标接口,AudioPlayer 是具体目标类,它可以直接播放 mp3 文件。AdvancedMediaPlayer 是高级媒体播放器接口,VlcPlayer 和 Mp4Player 是具体的高级媒体播放器类。

MediaAdapter 是适配器类,它实现了目标接口 MediaPlayer,并在内部封装了一个高级媒体播放器对象。根据传入的音频类型,它选择合适的高级媒体播放器来播放相应的文件。

在客户端代码中,我们首先创建一个 AudioPlayer 对象,然后直接使用它来播放 mp3 文件。接着,我们再使用适配器将 AudioPlayer 转换成 MediaPlayer 对象,并使用适配器对象来播放 vlc 文件和 mp4 文件。这样,即使目标接口和高级媒体播放器之间存在兼容性问题,我们也可以通过适配器将它们协同工作起来。

适配器模式的优缺点

适配器模式用于解决接口不兼容的问题。它将不同接口的对象进行转换,使其能够协同工作。适配器模式有以下优缺点:

优点:

  1. 解决接口不兼容问题:适配器模式能够处理不同接口之间的兼容性问题,使得不兼容的类能够协同工作。
  2. 重用现有功能:适配器模式可以重用已经存在的功能实现。通过适配器模式,我们可以使用已有的类来实现新的接口需求,而无需修改现有代码。
  3. 扩展性良好:通过适配器模式,可以轻松地添加新的适配器类来支持更多的对象和接口。

缺点:

  1. 增加复杂性:引入适配器会增加系统的复杂性和代码量,因为需要额外的适配器类来转换接口。
  2. 运行时效率损失:由于适配器会在客户端代码和适配者之间增加一层间接调用,可能会导致运行时的效率损失。
    总体来说,适配器模式是在接口不兼容的情况下使用的一种很有用的设计模式。它帮助我们解决了不同接口之间的兼容性问题,并能够重用现有代码。然而,适配器模式也会引入一些复杂性,需要权衡其使用时带来的好处和额外的成本。
相关推荐
雪度娃娃19 小时前
设计模式-UML
设计模式
kyriewen1119 小时前
代码写成一锅粥?3个设计模式让你的项目“起死回生”
开发语言·前端·javascript·设计模式·ecmascript
小风吹啊吹~20 小时前
vscode的tunnel链接(Linux 服务器 + Windows 本地电脑版本)
服务器·vscode·microsoft·远程工作
geovindu1 天前
go: Mediator Pattern
设计模式·golang·中介者模式
kyriewen1 天前
代码写成一锅粥?3个设计模式让你的项目“起死回生”
前端·javascript·设计模式
Pkmer2 天前
古法编程: 适配器模式
java·设计模式
宝桥南山2 天前
Microsoft Fabric - 尝试一下使用Shortcut Transformation进行数据同步
microsoft·ai·微软·database·powerbi·fabric
编码者卢布2 天前
【Azure App Service】为什么 Web App 上的文件会被“锁死“?
microsoft·azure·web app
蚰蜒螟2 天前
深入 Linux 内核同步机制:从 futex 到 spinlock 的完整旅程
linux·windows·microsoft