Java设计模式14:命令模式(Command)

Command

意图

将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作

动机

开发中,我们经常需要向某些对象发送请求,但是我们并不知道接收者是谁,也不知道被请求的操作是哪个,此时,我们特别希望能够以一种松耦合的方式来设计软件,使得请求发送者与请求接收者能够消除彼此之间的耦合,让对象之间的调用关系更加灵活,可以灵活地指定请求接收者以及被请求的操作。命令模式为此类问题提供了一个较为完美的解决方案。

命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。

适用性

1、系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者无须知道接收者的存在,也无须知道接收者是谁,接收者也无须关心何时被调用。

2、在不同的时刻制定、排列和执行请求

3、支持取消操作和恢复(Redo)操作。

4、支持修改日志

结构

这里写图片描述

Command

声明执行操作的接口,一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法

ConcreteCommand

将一个接收者对象绑定与一个动作,具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法

调用接收者相应的操作,实现execute( )方法

Invoker

请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。

Receiver

知道如何实施与执行一个请求相关的操作,它具体实现对请求的业务处理

实现

设计一个音乐播放器的功能

package command;

/**
 * @Author fitz.bai
 * @Date 2018/9/4 15:11
 * 接收者角色
 */
public class AudioPlayer {
    public void play() {
        System.out.println("play...");
    }

    public void rewind() {
        System.out.println("rewind...");
    }

    public void stop() {
        System.out.println("stop...");
    }

}
package command;

/**
 * @Author fitz.bai
 * @Date 2018/9/4 15:13
 * 抽象命令角色
 */
public interface Command {
    void execute();
}

package command;

/**
 * @Author fitz.bai
 * @Date 2018/9/4 15:13
 */
public class PlayCommand implements Command {

    private AudioPlayer audioPlayer;

    public PlayCommand(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }

    @Override
    public void execute() {
        audioPlayer.play();
    }
}

package command;

/**
 * @Author fitz.bai
 * @Date 2018/9/4 15:13
 */
public class RewindCommand implements Command {

    private AudioPlayer audioPlayer;

    public RewindCommand(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }

    @Override
    public void execute() {
        audioPlayer.rewind();
    }
}

package command;

/**
 * @Author fitz.bai
 * @Date 2018/9/4 15:13
 */
public class StopCommand implements Command {

    private AudioPlayer audioPlayer;

    public StopCommand(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }

    @Override
    public void execute() {
        audioPlayer.stop();
    }
}
package command;

/**
 * @Author fitz.bai
 * @Date 2018/9/4 15:15
 * 请求者角色
 */
public class KeyPad {
    private Command playCommand;
    private Command rewindCommand;
    private Command stopCommand;

    public void setPlayCommand(Command playCommand) {
        this.playCommand = playCommand;
    }

    public void setRewindCommand(Command rewindCommand) {
        this.rewindCommand = rewindCommand;
    }

    public void setStopCommand(Command stopCommand) {
        this.stopCommand = stopCommand;
    }

    public void play() {
        playCommand.execute();
    }

    public void rewind() {
        rewindCommand.execute();
    }

    public void stop() {
        stopCommand.execute();
    }
}
package command;

/**
 * @Author fitz.bai
 * @Date 2018/9/4 15:11
 */
public class Client {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();

        Command playCommand = new PlayCommand(audioPlayer);
        Command rewindCommand = new RewindCommand(audioPlayer);
        Command stopCommand = new StopCommand(audioPlayer);

        KeyPad keyPad = new KeyPad();
        keyPad.setPlayCommand(playCommand);
        keyPad.setRewindCommand(rewindCommand);
        keyPad.setStopCommand(stopCommand);

        keyPad.play();
        keyPad.rewind();
        keyPad.stop();
        keyPad.play();
        keyPad.stop();
    }
}

优点

1、降低系统的耦合度。请求者与接收者之间不存在直接引用,因此请求者与接收者之间实现完全解耦,相同的请求者可以对应不同的接收者,同样,相同的接收者也可以供不同的请求者使用,两者之间具有良好的独立性。

2、新的命令可以很容易地加入到系统中。无须修改原有系统源代码,满足“开闭原则”的要求。

3、可以比较容易地设计一个命令队列或宏命令(组合命令)。

4、为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案。

缺点

导致某些系统有过多的具体命令类。因为针对每一个对请求接收者的调用操作都需要设计一个具体命令类,因此在某些系统中可能需要提供大量的具体命令类,这将影响命令模式的使用

猜你喜欢

转载自blog.csdn.net/qq_22798455/article/details/82385928