命令模式/Command
意圖/適用場景:
命令模式是對命令的封裝。命令模式把發出命令的責任和執行命令的責任分割開,委派給不同的對象。
每一個命令都是一個操作:請求的一方發出請求要求執行一個操作;接收的一方收到請求,並執行操作。命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是被誰處理、是否被處理、何時處理以及怎麼處理。
命令模式有以下的優點:
- 允許請求方與接收方能夠獨立演化,使它們完全沒有關係,只需要面向命令就可以了;
- 命令本身也容易演化,新的命令容易被加入系統;
- 接收請求的一方靈活性很大,可以選擇接收與否,以及決定處理的細節;
- 容易設計一個命令隊列;
- 可以容易地實現命令歷史/日誌功能。
UML:
參與者:
- 命令(Command):所有命令的抽象接口。
- 具體命令(ConcreteCommand):定義命令的具體內容。
- 遞送者(Deliverer):負責命令的遞送過程。它從請求者那裏接收命令,並把命令分發到合適的地方去。這一角色的靈活性比較大,它可以維護一個命令隊列,可以記錄命令歷史。
- 請求者(Invoker):命令的來源。
- 接收者(Receiver):所有命令處理器的抽象接口。
- 具體接收者(ConcreteReceiver):具體化Receiver接口,實現處理命令的具體功能。
要點:
這裏描述的命令模式與《Java與模式》和《設計模式》中描述的命令者不大相同。
命令模式最關鍵的概念是把請求者、接收者以及命令三方解耦合,但這兩本書中所定義的模式結構以及給出的示例代碼不夠好。
這兩書中實例的好處在於從結構上把三方解耦,每一個角色都可以面向接口編程,在實現進有很大的選擇空間。
但是,它們互相之間仍然互相引用,不能說是完全解耦。一個更好的方法是引入一個遞送者角色,它負責命令的分發以及隊列的維護。這樣,三方者不需要再互相引用。而且在時序上看,可以做到異步遞送,擴展了系統的功能。
應用實例:
這種命令/消息式的實例實在是太多。
還是看AWT的事件模式,在責任鏈模式裏就講過,一個事件產生後,會被依次分發給各個Listener去嘗試處理,直到找到一個合適的處理者。
這裏,可以想象有一個事件處理器,即Deliverer;產生事件的構件就是Invoker,它把事件交給Deliverer,就不再過問這個事件的處理過程了;Deliverer把事件交給第一個監聽,也就是本模式中的Receiver,如果Receiver在handleEvent()中返回false,Deliverer還需要再找下一個Receiver。
示例代碼:
[java]
// Source code from file:ConcreteReceiver.java
packagedesignPatterns.Command;
publicclass ConcreteReceiver implements Receiver {
publicvoid handle(Event e) {
System.out.println("ConcreteReceiver.handle()");
}
}
// Source code from file:Deliverer.java
packagedesignPatterns.Command;
publicclass Deliverer extends Thread {
// This simulate a event queue, the length of the queue is 1 here.
privateEvent queue = null;
privateReceiver receiver = null;
publicDeliverer(Receiver receiver) {
this.receiver= receiver;
}
publicvoid deliver(Event e) {
queue = e;
}
publicvoid distribute(Event e) {
receiver.handle(e);
}
publicvoid run() {
intcount = 3;
while(count-- > 0) {
try{
sleep(1000);
if(null != queue) {
distribute(queue);
queue =null;
}
}catch (Exception e) {}
}
}
}
// Source code from file:Event.java
packagedesignPatterns.Command;
publicclass Event {
inttype;
intparameterA;
intparameterB;
}
// Source code from file:Invoker.java
packagedesignPatterns.Command;
publicclass Invoker {
Deliverer deliverer =null;
publicInvoker(Deliverer deliverer) {
this.deliverer= deliverer;
}
publicvoid act() {
Evente = new Event();
deliverer.deliver(e);
}
}
// Source code from file:Receiver.java
packagedesignPatterns.Command;
publicinterface Receiver {
publicvoid handle(Event e);
}
// Source code from file:User.java
packagedesignPatterns.Command;
publicclass User {
publicstatic void main(String[] args) {
Receiverreceiver = new ConcreteReceiver();
Deliverer deliverer =new Deliverer(receiver);
deliverer.start();
Invoker invoker =new Invoker(deliverer);
invoker.act();
}
}
[/java]