JAVA设计模式——命令模式

命令模式,又称为行动(Action)模式、交易(Transaction)模式,是一种行为型设计模式。命令模式的思想是:把一个请求或者操作封装到一个对象中,允许系统使用不同的请求把客户端参数化,从而实现对请求排队或者记录请求日志、提供命令的撤销和恢复功等能

命令模式涉及5个角色:

  • 客户(Client):创建一个具体命令对象并确定其接收者。
  • 抽象命令(Command):声明了一个给所有具体命令类的抽象接口。
  • 具体命令(Concrete Command):定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。
  • 请求者(Invoker):负责调用命令对象执行请求。
  • 接收者(Receiver):负责具体实施和执行一个请求。任何一个类都可以成为接收者。

结构图:
这里写图片描述

具体代码实现:

// 接收者
public class Receiver {
    public void action() {
        System.out.println("hey Geek!!");
    }
}

// 抽象命令
public interface Command {
    void execute();
}

// 具体命令
public class ConcreteCommand implements Command {
    private Receiver receiver; // 持有一个接收者引用

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.action();
    }
}

// 请求者
public class Invoker {
    private Command command; // 持有一个命令引用

    public Invoker(Command command) {
        this.command = command;
    }

    public void action() {
        command.execute();
    }
}

// 客户
public class Client {
    private Invoker invoker; // 持有一个请求者引用

    public void method() {
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(receiver); // 指定接收者
        invoker = new Invoker(command); // 指定命令
        invoker.action(); // 执行
    }
}

// 测试
class CommandTest {
    public static void main(String[] args) {
        Client client = new Client();
        client.method();
    }
}

运行结果:

hey Geek!!

可以看到请求者和接收者是松耦合的,因此要增删命令很容易就可以实现。

下面提供一个例子,一个录音机,有playrewindstop三个按键,分别对应播放、倒带、停止三个功能。另外还有个一个宏命令功能。

// 录音机,相当于接收者,实际上的功能拥有者
public class AudioPlayer {
    public void play() {
        System.out.println("playing...");
    }

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

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

// 抽象命令
public interface Command {
    void execute();
}

// 播放命令
public class PlayCommand implements Command {
    private AudioPlayer audioPlayer;

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

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

// 倒带命令
public class RewindCommand implements Command {
    private AudioPlayer audioPlayer;

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

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

// 停止命令
public class StopCommand implements Command {
    private AudioPlayer audioPlayer;

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

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

// 按键,相当于请求者
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();
    }
}

// 抽象宏
public interface Macro {
    void add(Command command); // 添加命令

    void removeLast(); // 删除最后添加的命令

    void execute(); // 依次执行列表中的命令
}

// 具体宏
public class MacroCommand implements Macro {
    private List<Command> list = new ArrayList<>(); // 持有一个命令列表引用

    @Override
    public void add(Command command) {
        list.add(command);
    }

    @Override
    public void removeLast() {
        list.remove(list.size()-1);
    }

    @Override
    public void execute() {
        list.forEach(Command::execute);
    }
}

// 用户
public class User {
    private AudioPlayer audioPlayer = new AudioPlayer();
    private Command playCommand = new PlayCommand(audioPlayer);
    private Command rewindCommand = new RewindCommand(audioPlayer);
    private Command stopCommand = new StopCommand(audioPlayer);

    // 方法一:使用普通的命令模式执行请求
    public void method1() {
        Keypad keypad = new Keypad();
        keypad.setPlayCommand(playCommand);
        keypad.setRewindCommand(rewindCommand);
        keypad.setStopCommand(stopCommand);

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

    // 方法二:使用宏的方式执行请求
    public void method2() {
        Macro macro = new MacroCommand();
        macro.add(playCommand);
        macro.add(stopCommand);
        macro.add(rewindCommand);
        macro.add(playCommand);
        macro.removeLast();
        macro.add(stopCommand);
        macro.execute();
    }


}

// 测试
class CommandTest {
    public static void main(String[] args) {
        User user = new User();
        user.method1();
        System.out.println("==========");
        user.method2();
    }
}

运行结果:

playing…
stopped!!
rewinding…
playing…
stopped!!
==========
playing…
stopped!!
rewinding…
stopped!!


总结

命令模式使得发起命令的对象——客户,和具体实现命令的对象——接收者对象完全解耦,也就是说发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。

命令模式把请求封装起来,可以动态地对它进行参数化、队列化和日志化等操作,从而使得系统更灵活。

命令模式中的命令对象能够很容易地组合成复合命令,也就是宏命令,从而使系统操作更简单,功能更强大。

由于发起命令的对象和具体的实现完全解耦,因此扩展新的命令就很容易,只需要实现新的命令对象,然后在装配的时候,把具体的实现对象设置到命令对象中,然后就可以使用这个命令对象,已有的实现完全不用变化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值