命令模式

2018-01-07  本文已影响25人  Leocat

命令模式(Command Pattern)

定义

Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.

将请求封装成对象,让你可以使用不同的请求来参数化客户端,支持请求队列或者记录请求日志,并且可以支持可撤销的操作。

类图定义如下:


命令模式

简单代码示例

// 接收者
public abstract class Receiver {
    // 业务逻辑在这里实现
    public abstract void doSomething();
}

public class ConcreteReceiver extends Receiver {
    public void doSomething() {
        // 具体业务的实现
    }
}

// 命令
public abstract class Command {
    public abstract void execute();
}

public class ConcreteCommand extends Command{

    private Receiver receiver;

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

    public void execute() {
        receiver.doSomething();
    }
}

// 调用者
public class Invoker {
    private Command command;//这里视情况用Command或者Queue<Command>等

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

    //执行命令
    public void action() {
        command.execute();
    }
}

// 客户端
public class Client {

    public static void main(String[] args) {

        // 创建Receiver,组装Command
        Receiver receiver = new ConcreteReceiver();
        Command command = new ConcreteCommand(receiver);

        // 调用Invoker执行命令
        Invoker invoker = new Invoker(command);
        invoker.action();
    }
}

JDK中的Command Pattern

JDK中的命令模式我们经常会用到,就是多线程中的Runnable。示例代码如下:

public class JDKCommand {

    public static void main(String[] args) {

        Runnable runnable = new MyRunnable(); // Command

        Thread thread = new Thread(runnable);  // Invoker

        thread.start(); // 调用Invoker执行命令
    }

    public static class MyRunnable implements Runnable {
        public void run() {
            // Run
        }
    }
}

我们仔细看代码,发现Commandinvoker都有了,但是没有发现Receiver
其实是因为我们在Commandrunnable)中把本应该由Receiver完成的业务逻辑给完成了,
所以其实Receiver已经融入到Command中了。

我们稍微变换一下,让Runnable符合我们上面的命令模式定义。示例如下:

public class JDKCommand2 {

    public static void main(String[] args) {

        Receiver receiver = new ConcreteReceiver(); // Receiver

        Runnable runnable = new MyRunnable(receiver); // Command

        Thread thread = new Thread(runnable);  // Invoker

        thread.start(); // 调用Invoker执行命令
    }

    public static class MyRunnable implements Runnable {

        private Receiver receiver;

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

        public void run() {
            receiver.doSomething();
        }
    }

    interface Receiver {
        void doSomething();
    }

    public static class ConcreteReceiver implements Receiver {
        public void doSomething() {
            System.out.println("Receiver: do something");
        }
    }
}

命令模式的应用

优点

调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。也就是解耦了命令的调用者和具体命令的执行者。

Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。

缺点

类膨胀问题:N个命令就需要N个Command子类

使用场景

只要你认为是命令的地方就可以采用命令模式,例如,在GUI开发中,一个按钮的点击是一个命令,可以采用命令模式;触发-反馈机制的处理等。

参考

命令模式的定义

上一篇 下一篇

猜你喜欢

热点阅读