命令模式用来将“请求”封装成对象,然后用命令对象来参数化其他对象,而且也可以支持撤销操作。短短一句话,概括了命令模式的精髓下面讲解一下这句话中暗藏的原则:
第一:每个命令都是一个对象,本身有执行(exectue)和撤销(undo)两个方法,那个这个对象在执行和撤销执行方法,总得有个执行对象吧?没错,这个对象就是我们的执行者(接受者)(receiver)。也就是真是完成命令下达真实动作的那个对象,毋庸置疑,这个对象肯定是要付给命令对象本身的。这样一旦命令被执行,命令对象才能知道让那个对象去执行要做的事情。
第二:为什么说是使用命令对象来参数化其他对象呢?其实,我们这个很好理解。比方说,我们去餐厅吃饭,首先服务员会给我们一个菜单,我们完成点单(创造一个命令对象,菜单就是我们的命令对象),交给服务员(用菜单参数化了服务员,对应于setCommand()),服务员就是我们的调用者对象,然后服务员合适时候就会将菜单交给做菜的厨师窗口,厨师得到菜单(厨师就是我们的receiver),开始做菜(执行命令)。
下面我们就来模拟一下这个问题:
第一步:首选我们创造一个命令类,这是一个超类,所有的命令类都是其子类,它规定所有的命令类都必须有执行(exectue)和撤销执行(undo)这两个功能。
public interface Command {
public void execute();
public void undo();
}
第二步:制造一个正式的命令子类
public class OrderCommand implements Command{
public Chef chef;
//创建命令的时候,就将这个命令到时候有谁来执行给指定好。
public OrderCommand (Chef chef){
this.chef = chef;
}
public void execute(){
chef.doFood();
}
public void undo(){
chef.undoFood();
}
}
第三步:把真正执行命令的对象(厨师)定义好,他完成命令真正要做的事情。
public class Chef {
public void doFood(){
System.out.println("我做了一道菜");
}
public void undoFood(){
System.out.println("这道菜顾客不要了,我就不做了。");
}
}
第四步:定义我们的调用者对象。也就是我们的服务员对象
public class Servier {
Command command ;
Command preCommand;//这个命令用来记录最近一次执行的命令。
public void setCommand(Command command){
this.command = command;
}
public void startService(){
command.execute();
preCommand = command;
}
public void undoService(){
preCommand.undo();
}
}
第五步:定义我们的客户对象。也就是客户端测试代码:
public class Client {
//这个类就是客户,想到与产生命令(菜单)的人
public static void main(String[] args) throws Exception{
//产生一个菜单(命令),并指明这个菜单(命令)由谁完成
Command orderCommand = new OrderCommand(new Chef());
Servier servier = new Servier();//完成一个点单(产生一个命令)
servier.setCommand(orderCommand);//将菜单给服务员。
servier.startService();//服务员将菜单交到厨师台。
Thread.sleep(5000);
servier.undoService();//撤销服务。
}
}
到此为止,命令模式例子既可以完成。下面我们把其对应的UML表示出来,以便于理解。
想一下,消息队列如何实现?其实就是一个线程对象不断执行送过来的命令对象罢了,线程对象不断的从队列总取出要执行的命令,然后开始执行。仅此而已。