命令模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式乍一看,有点懵懵的。即使这个定义看完,也是不明所以。但是结合例子来讲的话,就比较容易理解了。
其实它就是把一个类能做的事情,使用具体的对象Command类来包装一下,当客户端想调用某个方法的时候,他需要通过具体的Command类来进行调用,而不能直接实例化那个类然后调用类方法。这样的话就将类的调用和调用请求的发出者给相互隔离开,解耦了。这样具体的请求执行者就不需要关注,到底是谁发出的这个请求执行命令,只需要把要执行的命令执行完即可。
比如现在路边有一个三轮车的烧烤摊,烧烤摊只有一个老板负责点单、收款、烤肉、分发烤好的肉这些事情。那么这个老板其实就是行为实现者
,然后买烧烤的客人就是行为请求者
。在这种情况下,作为行为实现者
的老板,承担的事情职责就非常多,客户与老板紧耦合了,老板要处理的事情很多就非常容易出错,混乱。
而如果换一种方式,烧烤摊的老板赚到钱了,不再使用三轮车了,直接租了一个店面,招了一个服务员来帮忙。这下客人来吃烧烤的时候,就不用老板来负责点单、收款、分发烤肉的事情了,这些事情交给服务员来干,当客户需要烧烤的时候,只需要由服务员告诉老板需要几串羊肉串、几串五花肉即可,老板不需要知道这些烤串是哪个客户要的,他只需要把这些烤串烤完,交给服务员就行。这样老板和顾客就是松耦合了,老板只需要接收服务员的命令,即可有序、高效的完成烧烤订单。
这个行为请求者
与行为实现者
实现解耦的过程,其实就是命令模式了。它将客人的请求封装对象,由服务员统一接收,服务员接收完这些命令对象后,将命令对象转达给老板,老板统一执行这些命令,老板不需要关心谁发出的命令请求,直接执行完命令即可,这样就不会出现手忙脚乱的问题了。
下面以烧烤为例展示一下命令模式的代码
Receiver类是命令接受者对象,定义了命令接受者可以做的事情
public class Receiver {
public void bakeMutton(){
System.out.println("烤羊肉");
}
public void bakeBeef(){
System.out.println("烤牛肉");
}
public void bakeBread(){
System.out.println("烤面包");
}
public void bakeLobster(){
System.out.println("烤小龙虾");
}
}
Command类是命令抽象类,定义了一个命令接受者对象,以及命令执行的抽象方法
public abstract class Command {
protected Receiver receiver;
public Command(Receiver receiver) {
this.receiver = receiver;
}
public abstract void execute();
}
BakeBeefCommand烤牛肉类,是Command类的具体子类实现
public class BakeMuttonCommand extends Command{
public BakeMuttonCommand(Receiver receiver) {
super(receiver);
}
@Override
public void execute() {
receiver.bakeMutton();
}
}
BakeBreadCommand烤面包类,是Command类的具体子类实现
public class BakeBreadCommand extends Command{
public BakeBreadCommand(Receiver receiver) {
super(receiver);
}
@Override
public void execute() {
receiver.bakeBread();
}
}
BakeLobsterCommand烤小龙虾类,是Command的具体子类实现
public class BakeLobsterCommand extends Command{
public BakeLobsterCommand(Receiver receiver) {
super(receiver);
}
@Override
public void execute() {
receiver.bakeLobster();
}
}
BakeMuttonCommand烤羊肉串类,是Command的具体子类实现
public class BakeMuttonCommand extends Command{
public BakeMuttonCommand(Receiver receiver) {
super(receiver);
}
@Override
public void execute() {
receiver.bakeMutton();
}
}
Invoker类是具体命令的接收者,用于接收客户的所有命令,然后将命令转达给执行者,执行这些命令
public class Invoker {
private List<Command> command = new ArrayList<>();
public void setCommand(Command command) {
this.command.add(command);
}
public void executeCommand(){
for (Command comm : command) {
comm.execute();
}
}
}
public class MainApp {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new BakeMuttonCommand(receiver);
Command breadCommand = new BakeBreadCommand(receiver);
Command lobsterCommand = new BakeLobsterCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.setCommand(breadCommand);
invoker.setCommand(lobsterCommand);
invoker.executeCommand();
}
}
运行结果
烤羊肉
烤面包
烤小龙虾
命令模式能够实现将请求发出者和请求执行者进行解耦,便于实现请求的撤销、重做等操作。但是命令模式并不是一旦碰到类似情况的时候就要使用,而是要在确定需要使用的时候再使用,不要在自己猜测的基础上给系统增加不必要的功能,不能为了用命令模式而用命令模式,这点要考虑清楚。
这篇命令模式,感觉写的有点模模糊糊的,大家可以多看两遍示例代码理解一下。