定义
命令模式——将请求封装成对象,这可以让你使用不同的请求、队列,或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。
实例
餐厅点餐
以餐厅为例,顾客点餐,服务员记录订单,后移交给后厨制作。服务员是不用具体知道菜品是如何制作的,只需要记录下菜名,移交给后厨。服务员实际上将顾客和后厨解耦了,他们之间通过一个个菜品名,即一个个命令产生联系。不同的菜品可以互相组合,同样命令也可以互相组合。
下面列出餐厅对象与命令模式对象的对应关系:
餐厅 | 命令模式 |
---|---|
顾客 | Client |
订单 | Command |
厨师 | Receiver |
服务员 | Invoker |
移交订单 | setCommand() |
制作菜品 | execute() |
实现命令接口
首先,让所有的命令对象实现相同的包含一个方法的接口。在餐厅例子中,这个方法为制作菜品orderUp(),然而,现在改为一般惯用的名称execute()。这就是命令接口:
public interface Command {
public void execute();
}
实现一个制作鱼汤的命令
现在,菜单中有鱼汤这个菜品,厨师制作鱼汤,来看下如何实现成一个命令:
public class FishSoupCommand implements Command {
FishSoup fishSoup;
public FishSoupCommand(FishSoup fishSoup) {
this.fishSoup = fishSoup;
}
public void execute() {
// 制作鱼汤
FishSoup.cooking();
}
}
使用命令对象
把一切简化,看下这个订单如何完成:
public class SimpleOrder {
Command cmd;
public SimpleOrder() {}
public void setCommand(Command command) {
cmd = command;
}
// 点餐
public void orderUp() {
cmd.execute();
}
}
简单测试
下面来看顾客点了一个鱼汤后的测试代码:
// 这是命令模式的顾客
public class simpleOrderTest {
public statci void main(Stringp[] args) {
// 调用者,会传入一个命令对象,可以用来发出请求
SimpleOrder simpleOrder = new SimpleOrder();
FishSoup fishSoup = new FishSoup();
// 创建一个命令,将接收者传给它
FishSoupCommand fishSoupCommand = new FishSoupCommand(fishSoup);
// 把命令传给调用者
simpleOrder.setCommand(fishSoupCommand);
// 命令执行
simpleOrder.orderUp();
}
}
小结
-
命令模式将发出的对象和执行请求的对象解耦。
-
在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作。
-
调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用。
-
调用者可以接受命令当做参数,甚至在运行时动态地进行。
-
命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态。
-
宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销。
-
实际操作时,很常见使用聪明命令对象,也就是直接实现了请求,而不是将工作委托给接收者。
-
命令也可以用来实现日志和事务系统。