C++设计模式:适配器模式

什么是适配器模式?

适配器模式是一种结构型设计模式,用于解决接口不兼容的问题。通过适配器模式,我们可以将一个类的接口转换成客户端期望的接口,使得原本不能一起工作的类能够协同工作。简单来说,它的作用类似于电源适配器,将不兼容的插头接入到兼容的插座中。


适配器模式的应用场景
  1. 接口转换:当一个系统需要使用现有的类,但它的接口与系统的其他部分不兼容时,可以使用适配器模式。
  2. 集成遗留代码:当需要将旧系统集成到新系统中,而两者的接口不一致时,适配器模式是一种很好的解决方案。
  3. 接口统一:希望通过统一的接口来调用多种功能不同但相似的类。

适配器模式的组成

适配器模式的核心由以下三个部分组成:

  1. 目标接口(Target):定义客户端期望的接口标准。
  2. 适配者(Adaptee):现有的类,提供了功能但接口与目标接口不兼容。
  3. 适配器(Adapter):连接目标接口和适配者,负责接口的转换。

适配器模式的类图结构如下:

   ---------------------
  |      Client         |
   ---------------------
            |
            v
   ---------------------
  |    Target (接口)    |
   ---------------------
            ^
            |
   ---------------------
  |    Adapter (适配器) |
   ---------------------
            |
            v
   ---------------------
  |   Adaptee (被适配者) |
   ---------------------

贴近实际的案例:媒体播放器适配器

问题背景:

假设我们需要开发一个媒体播放器,它需要支持多种类型的文件播放:

  • 音频播放器支持 .mp3 文件。
  • 视频播放器支持 .mp4.avi 文件。

由于音频播放器和视频播放器的接口不同,我们希望通过统一的接口 MediaPlayer 来调用这些播放器的功能。


案例代码实现

以下是完整的适配器模式实现代码,并对每个模块进行中文解读。


目标接口(Target)
// 定义统一的播放器接口
class MediaPlayer {
public:
    virtual void play(const std::string& audioType, const std::string& fileName) = 0;
    virtual ~MediaPlayer() = default;
};

解读:
MediaPlayer 是客户端期望的接口,定义了一个 play() 方法,所有播放器类都必须实现该方法。客户端通过此接口来播放不同类型的媒体文件。


适配者(Adaptee)
#include <iostream>

// 高级媒体播放器接口
class AdvancedMediaPlayer {
public:
    virtual void playMp4(const std::string& fileName) = 0;
    virtual void playAvi(const std::string& fileName) = 0;
    virtual ~AdvancedMediaPlayer() = default;
};

// MP4 播放器
class Mp4Player : public AdvancedMediaPlayer {
public:
    void playMp4(const std::string& fileName) override {
        std::cout << "Playing mp4 file: " << fileName << std::endl;
    }

    void playAvi(const std::string& fileName) override {
        // 不支持播放 AVI 文件
        std::cout << "AVI format not supported by Mp4Player." << std::endl;
    }
};

// AVI 播放器
class AviPlayer : public AdvancedMediaPlayer {
public:
    void playMp4(const std::string& fileName) override {
        // 不支持播放 MP4 文件
        std::cout << "MP4 format not supported by AviPlayer." << std::endl;
    }

    void playAvi(const std::string& fileName) override {
        std::cout << "Playing avi file: " << fileName << std::endl;
    }
};

解读:

  • AdvancedMediaPlayer 是高级媒体播放器的接口,定义了两种高级格式(.mp4.avi)的播放方法。
  • Mp4PlayerAviPlayer 是具体的播放器实现类,分别实现了 .mp4.avi 的播放功能。

适配器(Adapter)
// 媒体适配器,将 AdvancedMediaPlayer 适配为 MediaPlayer
class MediaAdapter : public MediaPlayer {
private:
    AdvancedMediaPlayer* advancedMediaPlayer;

public:
    MediaAdapter(const std::string& audioType) {
        if (audioType == "mp4") {
            advancedMediaPlayer = new Mp4Player();
        } else if (audioType == "avi") {
            advancedMediaPlayer = new AviPlayer();
        } else {
            advancedMediaPlayer = nullptr;
        }
    }

    void play(const std::string& audioType, const std::string& fileName) override {
        if (audioType == "mp4") {
            advancedMediaPlayer->playMp4(fileName);
        } else if (audioType == "avi") {
            advancedMediaPlayer->playAvi(fileName);
        } else {
            std::cout << "Invalid media type: " << audioType << std::endl;
        }
    }

    ~MediaAdapter() {
        delete advancedMediaPlayer;
    }
};

解读:

  • MediaAdapter 适配器实现了 MediaPlayer 接口。
  • 根据媒体类型的不同,适配器创建对应的高级播放器实例(如 Mp4PlayerAviPlayer),并将 play() 方法调用委托给高级播放器。

具体播放器类
// 默认播放器,支持 MP3,使用适配器处理高级格式
class AudioPlayer : public MediaPlayer {
public:
    void play(const std::string& audioType, const std::string& fileName) override {
        if (audioType == "mp3") {
            std::cout << "Playing mp3 file: " << fileName << std::endl;
        } else if (audioType == "mp4" || audioType == "avi") {
            MediaAdapter adapter(audioType);
            adapter.play(audioType, fileName);
        } else {
            std::cout << "Unsupported media type: " << audioType << std::endl;
        }
    }
};

解读:
AudioPlayer 是客户端直接使用的播放器类:

  • 它可以直接播放 .mp3 文件。
  • 对于 .mp4.avi 文件,它会通过 MediaAdapter 适配器来处理。

客户端代码
int main() {
    AudioPlayer player;

    player.play("mp3", "song.mp3");
    player.play("mp4", "video.mp4");
    player.play("avi", "movie.avi");
    player.play("flv", "clip.flv"); // 不支持的格式

    return 0;
}

解读:
客户端使用 AudioPlayerplay() 方法播放不同类型的文件,完全不关心文件格式和具体的播放器实现。


运行结果
Playing mp3 file: song.mp3
Playing mp4 file: video.mp4
Playing avi file: movie.avi
Unsupported media type: flv

适配器模式优点
  1. 解耦:
    客户端与具体实现解耦,只依赖目标接口,代码更易于维护。

  2. 复用性:
    可以复用现有的类,而无需修改其代码。

  3. 扩展性:
    如果需要支持新的格式,只需添加新的高级播放器类,并扩展适配器逻辑即可。


适配器模式缺点
  1. 额外复杂度:
    适配器增加了一层间接调用,可能引入一定的复杂性。

  2. 性能影响:
    由于多了一层接口转换,可能对性能造成微小的影响(通常可以忽略不计)。


总结

适配器模式是软件开发中非常重要的模式之一,尤其在需要集成遗留系统或引入第三方库时,可以显著简化开发。通过适配器模式,我们可以在接口不一致的情况下,让系统更灵活地扩展和集成功能,同时遵循面向对象设计原则(如开闭原则和依赖倒置原则)。

以下是整合后的完整代码
#include <iostream>
#include <string>

// ===========================
// 目标接口(Target):定义客户端需要的统一接口
// ===========================
class MediaPlayer {
public:
    // 定义播放方法,接受文件类型和文件名作为参数
    virtual void play(const std::string& audioType, const std::string& fileName) = 0;
    virtual ~MediaPlayer() = default;
};

// ===========================
// 适配者接口(Adaptee):定义高级媒体播放器的接口
// ===========================
class AdvancedMediaPlayer {
public:
    // 播放 MP4 文件
    virtual void playMp4(const std::string& fileName) = 0;
    // 播放 AVI 文件
    virtual void playAvi(const std::string& fileName) = 0;
    virtual ~AdvancedMediaPlayer() = default;
};

// ===========================
// 具体适配者(Concrete Adaptee):MP4 播放器
// ===========================
class Mp4Player : public AdvancedMediaPlayer {
public:
    // 实现播放 MP4 文件的方法
    void playMp4(const std::string& fileName) override {
        std::cout << "Playing mp4 file: " << fileName << std::endl;
    }

    // 不支持播放 AVI 文件
    void playAvi(const std::string& fileName) override {
        std::cout << "AVI format not supported by Mp4Player." << std::endl;
    }
};

// ===========================
// 具体适配者(Concrete Adaptee):AVI 播放器
// ===========================
class AviPlayer : public AdvancedMediaPlayer {
public:
    // 不支持播放 MP4 文件
    void playMp4(const std::string& fileName) override {
        std::cout << "MP4 format not supported by AviPlayer." << std::endl;
    }

    // 实现播放 AVI 文件的方法
    void playAvi(const std::string& fileName) override {
        std::cout << "Playing avi file: " << fileName << std::endl;
    }
};

// ===========================
// 适配器(Adapter):将高级播放器接口适配为目标接口
// ===========================
class MediaAdapter : public MediaPlayer {
private:
    AdvancedMediaPlayer* advancedMediaPlayer; // 适配器持有高级播放器的引用

public:
    // 根据媒体类型选择适配的高级播放器
    MediaAdapter(const std::string& audioType) {
        if (audioType == "mp4") {
            advancedMediaPlayer = new Mp4Player();
        } else if (audioType == "avi") {
            advancedMediaPlayer = new AviPlayer();
        } else {
            advancedMediaPlayer = nullptr;
        }
    }

    // 将目标接口的调用转换为高级播放器接口的调用
    void play(const std::string& audioType, const std::string& fileName) override {
        if (audioType == "mp4") {
            advancedMediaPlayer->playMp4(fileName);
        } else if (audioType == "avi") {
            advancedMediaPlayer->playAvi(fileName);
        } else {
            std::cout << "Invalid media type: " << audioType << std::endl;
        }
    }

    // 析构函数,释放高级播放器实例
    ~MediaAdapter() {
        delete advancedMediaPlayer;
    }
};

// ===========================
// 具体播放器类(Concrete Target):实现默认的播放器逻辑
// ===========================
class AudioPlayer : public MediaPlayer {
public:
    // 实现统一的播放方法,支持 MP3,并通过适配器支持 MP4 和 AVI
    void play(const std::string& audioType, const std::string& fileName) override {
        if (audioType == "mp3") {
            // 如果是 MP3 文件,直接播放
            std::cout << "Playing mp3 file: " << fileName << std::endl;
        } else if (audioType == "mp4" || audioType == "avi") {
            // 对于 MP4 和 AVI 文件,使用适配器
            MediaAdapter adapter(audioType);
            adapter.play(audioType, fileName);
        } else {
            // 不支持的文件类型
            std::cout << "Unsupported media type: " << audioType << std::endl;
        }
    }
};

// ===========================
// 客户端代码:测试播放器功能
// ===========================
int main() {
    AudioPlayer player; // 创建播放器实例

    // 测试播放 MP3 文件
    player.play("mp3", "song.mp3");

    // 测试播放 MP4 文件
    player.play("mp4", "video.mp4");

    // 测试播放 AVI 文件
    player.play("avi", "movie.avi");

    // 测试播放不支持的文件类型
    player.play("flv", "clip.flv");

    return 0;
}

运行结果

Playing mp3 file: song.mp3
Playing mp4 file: video.mp4
Playing avi file: movie.avi
Unsupported media type: flv

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客晨风

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值