命令模式(Command Pattern)
定义
Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.
将请求封装成对象,让你可以使用不同的请求来参数化客户端,支持请求队列或者记录请求日志,并且可以支持可撤销的操作。
类图定义如下:
命令模式
-
Client(客户端)
负责建立具体命令(ConcreteCommand
)并组装接收者(Receiver
)。 -
Command(命令)
即需要执行的命令。 -
Receiver(接受者)
负责执行命令的内容,业务代码在Receiver
中实现。 -
Invoker(调用者)
接收到命令,并执行命令。
简单代码示例
// 接收者
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
}
}
}
我们仔细看代码,发现Command
、invoker
都有了,但是没有发现Receiver
。
其实是因为我们在Command
(runnable
)中把本应该由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开发中,一个按钮的点击是一个命令,可以采用命令模式;触发-反馈机制的处理等。
网友评论