命令模式包含如下角色:
Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
Client:客户类
有些时候我们想某个对象发送一个请求,但是我们并不知道该请求的具体接收者是谁,具体的处理过程是如何的,们只知道在程序运行中指定具体的请求接收者即可,对于这样将请求封装成对象的我们称之为命令模式。所以命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。同时命令模式支持可撤销的操作。
命令模式可以将请求的发送者和接收者之间实现完全的解耦,发送者和接收者之间没有直接的联系,发送者只需要知道如何发送请求命令即可,其余的可以一概不管,甚至命令是否成功都无需关心。同时我们可以非常方便的增加新的命令,但是可能就是因为方便和对请求的封装就会导致系统中会存在过多的具体命令类。
demo
入口类
package command_method_mod;
import org.junit.Test;
/**
* 命令模式
* 命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
*
* 介绍
* 意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
*
* 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
*
* 何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
*
* 如何解决:通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。
*
* 关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
*
* 应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。
*
* 优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
*
* 缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
*
* 使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。
*
* 注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式,见命令模式的扩展。
*
* 命令模式结构示意图:
*/
public class Client {
@Test
public void test(){
Invoker invoker = new Invoker();//调用者 发起人
Receiver receiver = new Receiver();//命令接收者 处理人
Command command1 = new OrderTakeout(receiver);//下单命令
Command command2 = new DeliverTakeout(receiver);//送货命令
Command command3 = new ReciveTakeout(receiver);//收取货物
invoker.setCommand(command1);//调用者 发起下单命令(暂存)
invoker.setCommand(command2);//调用者 发起送货命令(暂存)
invoker.setCommand(command3);//调用者 发起收货命令(暂存)
invoker.call();//一次性递交所有暂存命令
//命令执行结果
// 下單成功,請及時送貨上門
// 正在送貨路上,路上堵車,會遲到10分鐘
// 已收到訂單,快遞時間有點久,不太滿意
}
}
调用者,命令使用者
package command_method_mod;
import java.util.ArrayList;
import java.util.List;
/**
* Invoker:负责调用命令对象执行请求,相关的方法叫做行动方法。
*/
public class Invoker {
List<Command> commands = new ArrayList<>();
public void setCommand(Command command) {
commands.add(command);
}
public void call() {
commands.forEach((command -> command.execute()));
commands.clear();//調用完之後需要清空
}
}
命令抽象接口
package command_method_mod;
/**
* Command:声明了一个命令类的抽象接口。
*/
public interface Command {
void execute();//execute()方法通常叫做执行方法。
}
命令执行者,命令实施人
package command_method_mod;
/**
* Receiver:具体执行请求操作类,其具体方法叫行动方法。
*/
public class Receiver {
public void order(){
System.out.println("下單成功,請及時送貨上門");
}
public void deliver(){
System.out.println("正在送貨路上,路上堵車,會遲到10分鐘");
}
public void receiver(){
System.out.println("已收到訂單,快遞時間有點久,不太滿意");
}
}
具体命令 1
package command_method_mod;
/**
* ConcreteCommand:定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。
*/
public class DeliverTakeout implements Command {
private Receiver receiver;
public DeliverTakeout(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.deliver();
}
}
具体命令 2
package command_method_mod;
/**
* ConcreteCommand:定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。
*/
public class OrderTakeout implements Command {
private Receiver receiver;
public OrderTakeout(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.order();
}
}
具体命令 3
package command_method_mod;
/**
* ConcreteCommand:定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。
*/
public class ReciveTakeout implements Command {
private Receiver receiver;
public ReciveTakeout(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.receiver();
}
}
设计模式概览