JavaScript设计模式「基于ES2024」:结构型模式-适配器模式

71 阅读2分钟

适配器模式允许不兼容的接口之间进行协作,这种模式在集成新的或已存在的组件到现有系统时特别有用,特别是当这些组件的接口与系统期望的接口不匹配时更是一把利器。

// 目标接口
class MediaPlayer {
    play(audioType, fileName) {
        throw new Error('Method not implemented');
    }
}

// 具体的音频播放器,只支持 MP3 格式
class AudioPlayer extends MediaPlayer {
    play(audioType, fileName) {
        if (audioType !== 'mp3') {
            console.log(`Invalid media. ${audioType} format not supported`);
            return;
        }
        console.log(`Playing mp3 file. Name: ${fileName}`);
    }
}

// 高级媒体播放器接口
class AdvancedMediaPlayer {
    playVlc(fileName) {
        throw new Error('Method not implemented');
    }
    
    playMp4(fileName) {
        throw new Error('Method not implemented');
    }
}

// 具体的 VLC 播放器
class VlcPlayer extends AdvancedMediaPlayer {
    playVlc(fileName) {
        console.log(`Playing vlc file. Name: ${fileName}`);
    }
    
    playMp4(fileName) {
        // 什么也不做
    }
}

// 具体的 MP4 播放器
class Mp4Player extends AdvancedMediaPlayer {
    playVlc(fileName) {
        // 什么也不做
    }
    
    playMp4(fileName) {
        console.log(`Playing mp4 file. Name: ${fileName}`);
    }
}

// 媒体适配器
class MediaAdapter extends MediaPlayer {
    #advancedMusicPlayer;

    constructor(audioType) {
        super();
        if (audioType === 'vlc') {
            this.#advancedMusicPlayer = new VlcPlayer();
        } else if (audioType === 'mp4') {
            this.#advancedMusicPlayer = new Mp4Player();
        }
    }

    play(audioType, fileName) {
        if (audioType === 'vlc') {
            this.#advancedMusicPlayer.playVlc(fileName);
        } else if (audioType === 'mp4') {
            this.#advancedMusicPlayer.playMp4(fileName);
        }
    }
}

// 增强的音频播放器
class EnhancedAudioPlayer extends AudioPlayer {
    #mediaAdapter;

    play(audioType, fileName) {
        if (audioType === 'mp3') {
            super.play(audioType, fileName);
        } else if (audioType === 'vlc' || audioType === 'mp4') {
            this.#mediaAdapter = new MediaAdapter(audioType);
            this.#mediaAdapter.play(audioType, fileName);
        } else {
            console.log(`Invalid media. ${audioType} format not supported`);
        }
    }
}

// 使用示例
const player = new EnhancedAudioPlayer();

player.play('mp3', 'beyond_the_horizon.mp3');
player.play('mp4', 'alone.mp4');
player.play('vlc', 'far_far_away.vlc');
player.play('avi', 'mind_me.avi');

实现思路

  1. MediaPlayer 接口: 定义了基本的媒体播放器接口。
  2. AudioPlayer: 实现了 MediaPlayer 接口,但只支持 MP3 格式。
  3. AdvancedMediaPlayer 接口: 定义了高级媒体播放器的接口,支持 VLC 和 MP4 格式。
  4. VlcPlayerMp4Player: 实现了 AdvancedMediaPlayer 接口,分别支持 VLC 和 MP4 格式。
  5. MediaAdapter:
    • 继承自 MediaPlayer
    • 内部使用 AdvancedMediaPlayer 的实例,根据音频类型选择合适的播放器。
  6. EnhancedAudioPlayer:
    • 继承自 AudioPlayer
    • 使用 MediaAdapter 来支持额外的音频格式。

优点

  • 分离接口: 客户端代码可以与现有接口一起工作,而不需要修改。
  • 可扩展性: 可以轻松添加新的适配器来支持更多的音频格式。
  • 单一职责原则: 将接口转换的逻辑从主要业务逻辑中分离出来。
  • 开闭原则: 可以引入新类型的适配器而不会破坏现有代码。