[设计模式]中介者模式

    中介者模式,这个模式用来解耦类与类之间的复杂关系。

    我在项目中使用中介者用来处理音乐播放器的多入口控制问题。首先是需求:带屏智能音箱在播放音乐的时候控制的入口有两个,界面和语音,播放器只有一个,为了解耦多个控制者和一个执行者,所以采用了中介者模式。这样控制者与中介者交互、中介者与执行者交互,解决了多个控制者之间的控制冲突。

    下面来看看代码的实现:

首先是中介者基类:

/**
 * 中介者模式基类,只有一个方法notice用来通知
 */
public interface BaseMediaEventMediator {
    void notice(MediaEventUser mediaEventUser, Message message);
}

然后是所有中介者下用户的基类:

public abstract class MediaEventUser {

    protected BaseMediaEventMediator baseMediaEventMediator;

    public MediaEventUser(BaseMediaEventMediator baseMediaEventMediator) {
        this.baseMediaEventMediator = baseMediaEventMediator;
    }

    public boolean handleMessage(Message message) {
        return false;
    }
}

用户 -> 控制者,也就是界面和语音控制:

/**
 * 音乐的命令者,通过baseMediaEventMediator的notice方法来通知执行者,然后通过回调来获取执行者当前的状态
 */
public class MediaEventCommander extends MediaEventUser {

    private Message message;
    private MediaEventCommanderCallback mediaEventCommanderCallback;

    public MediaEventCommander(BaseMediaEventMediator baseMediaEventMediator, MediaEventCommanderCallback mediaEventCommanderCallback) {
        super(baseMediaEventMediator);
        this.mediaEventCommanderCallback = mediaEventCommanderCallback;
    }

    public void commandStartPlay() {
        message = new Message();
        message.what = MediaEvent.COMMAND_START_PLAY;
        noticeExecutor(message);
    }

    public void commandStopPlay() {
        message = new Message();
        message.what = MediaEvent.COMMAND_STOP_PLAY;
        noticeExecutor(message);
    }

    public void commandPausePlay() {
        message = new Message();
        message.what = MediaEvent.COMMAND_PAUSE_PLAY;
        noticeExecutor(message);
    }

    public void commandResumePlay() {
        message = new Message();
        message.what = MediaEvent.COMMAND_RESUME_PLAY;
        noticeExecutor(message);
    }

    public void commandFastForward(Integer value) {
        message = new Message();
        message.what = MediaEvent.COMMAND_FAST_FORWARD;
        message.obj = value;
        noticeExecutor(message);
    }

    public void commandFastBackward(Integer value) {
        message = new Message();
        message.what = MediaEvent.COMMAND_FAST_BACKWARD;
        message.obj = value;
        noticeExecutor(message);
    }

    public void commandChangePlayModel(PlayModel model) {
        message = new Message();
        message.what = MediaEvent.COMMAND_CHANGE_PLAYMODEL;
        message.obj = model;
        noticeExecutor(message);
    }

    public void commandNext() {
        message = new Message();
        message.what = MediaEvent.COMMAND_NEXT;
        noticeExecutor(message);
    }

    public void commandPrevious() {
        message = new Message();
        message.what = MediaEvent.COMMAND_PREVIOUS;
        noticeExecutor(message);
    }

    public void commandIndex(Integer index) {
        message = new Message();
        message.what = MediaEvent.COMMAND_INDEX;
        message.obj = index;
        noticeExecutor(message);
    }

    public void commandChangeProcess(Integer process) {
        message = new Message();
        message.what = MediaEvent.COMMAND_CHANGE_PROCESS;
        message.obj = process;
        noticeExecutor(message);
    }

    public void requestPlayingAudio() {
        message = new Message();
        message.what = MediaEvent.REQUEST_PLAYING_AUDIO;
        noticeExecutor(message);
    }

    public void requestAudioList() {
        message = new Message();
        message.what = MediaEvent.REQUEST_AUDIOLIST;
        noticeExecutor(message);
    }

    private void noticeExecutor(Message message) {
        baseMediaEventMediator.notice(this, message);
    }

    @Override
    public boolean handleMessage(Message message) {
        switch (message.what) {
            case MediaEvent.EXECUTOR_START_PALY:
                mediaEventCommanderCallback.onMediaStart((AudioBean) message.obj);
                break;
            case MediaEvent.EXECUTOR_STOP_PALY:
                mediaEventCommanderCallback.onMediaPause();
                break;
            case MediaEvent.COMMAND_PAUSE_PLAY:
                mediaEventCommanderCallback.onMediaPause();
                break;
            case MediaEvent.EXECUTOR_ERROR_PALY:
                mediaEventCommanderCallback.onMediaError((ExoPlayerManager.MediaPlayerError) message.obj);
                break;
            case MediaEvent.EXECUTOR_CHANGE_PLAYMODEL:
                mediaEventCommanderCallback.onMediaChangePlayModel((PlayModel) message.obj);
                break;
            case MediaEvent.RETURN_PALYING_AUDIO:
                mediaEventCommanderCallback.returnPlayingMediaAudio((AudioBean) message.obj);
                break;
            case MediaEvent.RETURN_AUDIOLIST:
                mediaEventCommanderCallback.returnMediaAudioList((List<AudioBean>) message.obj);
                break;
            case MediaEvent.RETURN_LYRIC:
                mediaEventCommanderCallback.returnLyric((File) message.obj);
                break;
        }
        return super.handleMessage(message);
    }

    public interface MediaEventCommanderCallback {

        void onMediaStart(AudioBean audioBean);

        void onMediaPause();

        void onMediaError(ExoPlayerManager.MediaPlayerError mediaPlayerError);

        void onMediaChangePlayModel(PlayModel model);

        void returnPlayingMediaAudio(AudioBean audioBean);

        void returnMediaAudioList(List<AudioBean> audioBeans);

        void returnLyric(File lyricFile);
    }
}

用户 -> 执行者,也就是音乐播放器:

/**
 * 音乐的执行者,通过baseMediaEventMediator的notice方法来通知命令者,然后通过回调来获取命令者的指令
 */
public class MediaEventExecutor extends MediaEventUser {

    private Message message;
    private MediaEventExecutorCallback mediaEventExecutorCallback;

    public MediaEventExecutor(BaseMediaEventMediator baseMediaEventMediator, @NonNull MediaEventExecutorCallback mediaEventExecutorCallback) {
        super(baseMediaEventMediator);
        this.mediaEventExecutorCallback = mediaEventExecutorCallback;
    }

    public void executorStartPlay(AudioBean audioBean) {
        message = new Message();
        message.what = MediaEvent.EXECUTOR_START_PALY;
        message.obj = audioBean;
        noticeCommander(message);
    }

    public void executorPausePlay() {
        message = new Message();
        message.what = MediaEvent.EXECUTOR_STOP_PALY;
        noticeCommander(message);
    }

    public void executorError(ExoPlayerManager.MediaPlayerError mediaPlayerError) {
        message = new Message();
        message.what = MediaEvent.EXECUTOR_ERROR_PALY;
        message.obj = mediaPlayerError;
        noticeCommander(message);
    }

    public void executorChangePlayModel(PlayModel playModel) {
        message = new Message();
        message.what = MediaEvent.EXECUTOR_CHANGE_PLAYMODEL;
        message.obj = playModel;
        noticeCommander(message);
    }

    public void returnAudio(AudioBean audioBean) {
        message = new Message();
        message.what = MediaEvent.RETURN_PALYING_AUDIO;
        message.obj = audioBean;
        noticeCommander(message);
    }

    public void returnAudioList(List<AudioBean> audioBeans) {
        message = new Message();
        message.what = MediaEvent.RETURN_AUDIOLIST;
        message.obj = audioBeans;
        noticeCommander(message);
    }

    public void returnLyric(File file) {
        message = new Message();
        message.what = MediaEvent.RETURN_LYRIC;
        message.obj = file;
        noticeCommander(message);
    }

    private void noticeCommander(Message message) {
        baseMediaEventMediator.notice(this, message);
    }

    @Override
    public final boolean handleMessage(Message message) {
        switch (message.what) {
            case MediaEvent.COMMAND_START_PLAY:
                return mediaEventExecutorCallback.startPlay();
            case MediaEvent.COMMAND_STOP_PLAY:
                return mediaEventExecutorCallback.stopPlay();
            case MediaEvent.COMMAND_PAUSE_PLAY:
                return mediaEventExecutorCallback.pausePlay();
            case MediaEvent.COMMAND_RESUME_PLAY:
                return mediaEventExecutorCallback.resumePlay();
            case MediaEvent.COMMAND_FAST_FORWARD:
                return mediaEventExecutorCallback.fastForward((Integer) message.obj);
            case MediaEvent.COMMAND_FAST_BACKWARD:
                return mediaEventExecutorCallback.fastBackward((Integer) message.obj);
            case MediaEvent.COMMAND_CHANGE_PLAYMODEL:
                return mediaEventExecutorCallback.changePlayModel((PlayModel) message.obj);
            case MediaEvent.COMMAND_NEXT:
                return mediaEventExecutorCallback.next();
            case MediaEvent.COMMAND_PREVIOUS:
                return mediaEventExecutorCallback.previous();
            case MediaEvent.COMMAND_INDEX:
                return mediaEventExecutorCallback.index((Integer) message.obj);
            case MediaEvent.COMMAND_CHANGE_PROCESS:
                return mediaEventExecutorCallback.changeProcess((Integer) message.obj);
            case MediaEvent.REQUEST_PLAYING_AUDIO:
                return mediaEventExecutorCallback.getPlayingAudio();
            case MediaEvent.REQUEST_AUDIOLIST:
                return mediaEventExecutorCallback.getAudioBeans();
            default:
                break;
        }
        return super.handleMessage(message);
    }

    public interface MediaEventExecutorCallback {
        boolean startPlay();

        boolean stopPlay();

        boolean pausePlay();

        boolean resumePlay();

        boolean fastForward(Integer value);

        boolean fastBackward(Integer value);

        boolean changePlayModel(PlayModel model);

        boolean next();

        boolean previous();

        boolean index(Integer index);

        boolean changeProcess(Integer process);

        boolean getPlayingAudio();

        boolean getAudioBeans();
    }
}

最后是中介者的实现:

/**
 * 中介者模式实现
 */
public class MediaEventMediator implements BaseMediaEventMediator {

    private static final String TAG = "MediaEventMediator";
    private int mediaType;

    private MediaEventMediator() {
        mediaType = Constant.MEDIA_TYPE_MUSIC;
    }

    private static MediaEventMediator instance = new MediaEventMediator();

    public static MediaEventMediator getInstance() {
        return instance;
    }

    //音乐的中介者允许有多个命令者Commander(Activity、Service)
    private List<MediaEventCommander> commanders = new ArrayList<>();
    //音乐的中介者模式只允许一个执行者Executor
    private MediaEventExecutor executor;

    public void addCommander(MediaEventCommander commander) {
        commanders.add(commander);
    }

    public void removeCommander(MediaEventCommander commander) {
        commanders.remove(commander);
    }

    public void setExecutor(MediaEventExecutor executor) {
        this.executor = executor;
    }

    //实现基类的notice方法,通过Message来携带参数
    @Override
    public void notice(MediaEventUser mediaEventUser, Message message) {
        LogUtil.d(TAG, "notice: 中介者收到消息:mediaEventUser.getClass() = " + mediaEventUser.getClass().getName()
                + ";message.what = " + message.what
                + ";message.obj = " + message.obj);
        if ("com.soundai.music.mediators.MediaEventCommander".equals(mediaEventUser.getClass().getName())) {
            if (executor != null) {
                boolean flag = executor.handleMessage(message);
                LogUtil.d(TAG, "notice: 处理结果:flag = " + flag);
            }
        } else if ("com.soundai.music.mediators.MediaEventExecutor".equals(mediaEventUser.getClass().getName())) {
            for (MediaEventCommander commander : commanders) {
                commander.handleMessage(message);
            }
        }
    }
}

代码部分就到此为止了,从我的感觉上来说,中介者模式的好处在于:把对象和对象之间的耦合降低了,比如上面的命令者和执行者,在加入了中介者之后,执行者就只需要关心自己的业务逻辑然后跟中介者交互,命令者同理。这样的缺点也很明显:所有的交互相关的逻辑都在中介者中处理,中介者可能后续的逻辑会越来越复杂,而且一旦中介者出了问题,那么整条链路可能都会出现问题。

发布了61 篇原创文章 · 获赞 2 · 访问量 8716

猜你喜欢

转载自blog.csdn.net/woaily1346/article/details/94007109
今日推荐