命令模式/Command

意图/适用场景:
命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。
每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是被谁处理、是否被处理、何时处理以及怎么处理。
命令模式有以下的优点:

  1. 允许请求方与接收方能够独立演化,使它们完全没有关系,只需要面向命令就可以了;
  2. 命令本身也容易演化,新的命令容易被加入系统;
  3. 接收请求的一方灵活性很大,可以选择接收与否,以及决定处理的细节;
  4. 容易设计一个命令队列;
  5. 可以容易地实现命令历史/日志功能。

UML:

命令模式/Command

参与者:

  1. 命令(Command):所有命令的抽象接口。
  2. 具体命令(ConcreteCommand):定义命令的具体内容。
  3. 递送者(Deliverer):负责命令的递送过程。它从请求者那里接收命令,并把命令分发到合适的地方去。这一角色的灵活性比较大,它可以维护一个命令队列,可以记录命令历史。
  4. 请求者(Invoker):命令的来源。
  5. 接收者(Receiver):所有命令处理器的抽象接口。
  6. 具体接收者(ConcreteReceiver):具体化Receiver接口,实现处理命令的具体功能。

要点:
这里描述的命令模式与《Java与模式》和《设计模式》中描述的命令者不大相同。
命令模式最关键的概念是把请求者、接收者以及命令三方解耦合,但这两本书中所定义的模式结构以及给出的示例代码不够好。
这两书中实例的好处在于从结构上把三方解耦,每一个角色都可以面向接口编程,在实现进有很大的选择空间。
但是,它们互相之间仍然互相引用,不能说是完全解耦。一个更好的方法是引入一个递送者角色,它负责命令的分发以及队列的维护。这样,三方者不需要再互相引用。而且在时序上看,可以做到异步递送,扩展了系统的功能。

应用实例:
这种命令/消息式的实例实在是太多。
还是看AWT的事件模式,在责任链模式里就讲过,一个事件产生后,会被依次分发给各个Listener去尝试处理,直到找到一个合适的处理者。
这里,可以想象有一个事件处理器,即Deliverer;产生事件的构件就是Invoker,它把事件交给Deliverer,就不再过问这个事件的处理过程了;Deliverer把事件交给第一个监听,也就是本模式中的Receiver,如果Receiver在handleEvent()中返回false,Deliverer还需要再找下一个Receiver。

示例代码:

   [java]
// Source code from file:  ConcreteReceiver.java

package designPatterns.Command;

public class ConcreteReceiver implements Receiver {
public void handle(Event e) {
System.out.println("ConcreteReceiver.handle()");
}
}

// Source code from file:  Deliverer.java

package designPatterns.Command;

public class Deliverer extends Thread {

// This simulate a event queue, the length of the queue is 1 here.
private Event queue = null;
private Receiver receiver = null;

public Deliverer(Receiver receiver) {
this.receiver = receiver;
}

public void deliver(Event e) {
queue = e;
}

public void distribute(Event e) {
receiver.handle(e);
}

public void run() {
int count = 3;
while (count-- > 0) {
try {
sleep(1000);
if (null != queue) {
distribute(queue);
queue = null;
}
} catch (Exception e) {}
}
}
}

// Source code from file:  Event.java

package designPatterns.Command;

public class Event {
int type;
int parameterA;
int parameterB;
}

// Source code from file:  Invoker.java

package designPatterns.Command;

public class Invoker {

Deliverer deliverer = null;

public Invoker(Deliverer deliverer) {
this.deliverer = deliverer;
}

public void act() {
Event e = new Event();
deliverer.deliver(e);
}
}

// Source code from file:  Receiver.java

package designPatterns.Command;

public interface Receiver {
public void handle(Event e);
}

// Source code from file:  User.java

package designPatterns.Command;

public class User {
public static void main(String[] args) {
Receiver receiver = new ConcreteReceiver();
Deliverer deliverer = new Deliverer(receiver);
deliverer.start();
Invoker invoker = new Invoker(deliverer);
invoker.act();
}
}
[/java]