设计模式之命令模式

Command design pattern

命令模式的概念、命令模式的结构、命令模式的优缺点、命令模式的使用场景、命令模式的实现示例、命令模式的源码分析


1、命令模式的概念

  命令模式,即将请求封装成一个对象,使发出请求的责任和执行请求的责任分离开。这样两者之间通过命令对象进行沟通,方便讲命令对象进行存储、传递、调用和管理。

2、命令模式的结构

  • 抽象命令:定义执行命令的行为。
  • 实现者/接受者:命令的实现者或接受者,真正执行命令的对象。任何类都可以成为一个接受者,只要它能够实现命令所要求的功能。
  • 具体命令:实现抽象命令,持有接受者的引用,通过委托调用接受者执行命令的方法来实现命令的行为。
  • 调用者/请求者:即命令请求,命令发起者,持有命令对象的引用,它可以持有多个命令,即可以一次性发出多个命令。它是客户端真正出发命令并要求命令执行的地方,也就是相当于使用命令对象的入口。

command-class

3、命令模式的优缺点

  • 优点:
    • 降低系统的耦合度。即降低命令请求者与执行者的耦合度。
    • 满足开闭原则,增加命令或删除命令不影响其它类,扩展灵活。
    • 可实现宏命令,命令模式可与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
    • 方便实现 Undo 和 Redo 操作,命令模式可与备忘录模式结合,实现命令的撤销和恢复。
  • 缺点:
    • 导致系统有过多的具体命令类,增加系统复杂度。

4、命令模式的使用场景

  • 当需要讲请求者调用者和请求接受者解耦时。
  • 当需要在不同的时间指定请求,将请求排队和执行请求。
  • 当需要支持命令的撤销操作和恢复操作时。

5、命令模式的实现示例

接受者:

public class Receiver {

    /**
     * 命令接受者执行命令
     * @param name
     */
    public void attack(String name) {
        System.out.println(name);
    }
}

抽象命令:

public interface Command {

    /**
     * 执行命令
     */
    void execute();
}

具体命令:

public class ZedCommand implements Command {

    private String name;

    private Receiver receiver;

    public ZedCommand(String name, Receiver receiver) {
        this.name = name;
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.attack(this.name);
    }
}

调用者:

public class Invoker {

    private List<Command> commands;

    public Invoker() {
        this.commands = new ArrayList<>();
    }

    public void addCommand(Command command) {
        this.commands.add(command);
    }

    /**
     * 发出命令
     */
    public void commands() {
        for (Command command : this.commands) {
            command.execute();
        }
    }
}

测试:

public class CommandTest {

    public static void main(String[] args) {
        Invoker invoker = new Invoker();

        Receiver receiver = new Receiver();

        invoker.addCommand(new ZedCommand("禁奥义·瞬狱影杀阵", receiver));
        invoker.addCommand(new ZedCommand("影奥义·分身", receiver));
        invoker.addCommand(new ZedCommand("影奥义·鬼斩", receiver));
        invoker.addCommand(new ZedCommand("影奥义·诸刃", receiver));
        invoker.addCommand(new ZedCommand("影奥义·分身", receiver));
        invoker.addCommand(new ZedCommand("影忍法·灭魂劫", receiver));
        invoker.addCommand(new ZedCommand("禁奥义·瞬狱影杀阵", receiver));

        invoker.commands();
    }
}

测试结果:

禁奥义·瞬狱影杀阵
影奥义·分身
影奥义·鬼斩
影奥义·诸刃
影奥义·分身
影忍法·灭魂劫
禁奥义·瞬狱影杀阵

6、命令模式的源码分析

  jdk 中的 Runnable 接口的设计就是一个典型的命令模式。Runnable 接口担当命令角色,Thread 则是调用者,start 方法就是命令执行方法。

// 抽象命令
public interface Runnable {
  	// 执行命令
    public abstract void run();
}
public class Thread implements Runnable {
  	// 持有命令的引用
  	private Runnable target;
  public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();
}

  通过源码可以发现,其在发出命令调用时会调用一个本地方法 start0(),开启一个县城。而接受者是对外开放的,即程序员可以自己定义接受者。

命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使得请求的发送者和接收者解耦。在命令模式中,请求以命令的形式包裹在对象中,并传递给调用对象。调用对象寻找可以处理该命令的合适的对象,并将命令传递给相应的对象,该对象执行命令。 在C语言中,可以使用函数指针来实现命令模式。具体步骤如下: 1. 定义一个命令接口,该接口包含一个执行命令的方法。 2. 创建具体的命令类,实现命令接口,并在执行方法中调用相应的函数。 3. 创建一个调用者类,该类包含一个命令对象,并提供一个执行命令的方法。 4. 在调用者类中,将命令对象传递给相应的对象,并调用命令对象的执行方法。 下面是一个简单的示例代码: ```c #include <stdio.h> // 定义命令接口 typedef struct { void (*execute)(void); } Command; // 创建具体的命令类 typedef struct { Command command; void (*function)(void); } ConcreteCommand; void concreteCommand_execute(void) { printf("执行具体的命令\n"); } // 创建调用者类 typedef struct { Command *command; void (*setCommand)(Command *command); void (*executeCommand)(void); } Invoker; void invoker_setCommand(Command *command) { Invoker *invoker = (Invoker *)command; invoker->command = command;} void invoker_executeCommand(void) { Invoker *invoker = (Invoker *)invoker->command; invoker->command->execute(); } int main() { // 创建具体的命令对象 ConcreteCommand concreteCommand; concreteCommand.command.execute = concreteCommand_execute; concreteCommand.function = concreteCommand_execute; // 创建调用者对象 Invoker invoker; invoker.setCommand((Command *)&concreteCommand); invoker.executeCommand(); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值