命令模式(我的理解)

xyz發表於2006-04-12
命令模式(我的理解)
前言
第一章:通常的命令模式
第二章:簡化的命令模式
第三章:其他要說的內容
前言
以下是我對命令模式的理解。可能和很多其他文章講述的不太一樣。經過我理解加工的。供大家參考!學藝不精,並且寫的比較倉促,還請大家指教。
通常的命令模式:
1.1通常命令模式有一下幾個角色
呼叫者:(命令的執行者)
生成有序的命令佇列
按順序執行命令操作
提供撤銷命令操作
記錄已經操作的命令
抽象命令:
抽象的命令介面
具體命令:
具體的命令。
由三個要素組成:執行者,執行者要作的操作和被執行的物件組成。當然還可以有其他,比如將物件執行成什麼結果。例如:呼叫Mypait類(執行者)將My rectangle(物件)填充(操作)為紅色(結果)。這樣就可以完全描述一個命令了。
執行者:
真正執行邏輯操作的物件

1.2原型:

//呼叫者
public class Invoker{
List commands; //命令集合

public void setCommands(List commands){
this.commands = commands;
}

public void addCommand (Command command,int i){
commands.add(i,command);
}
public void removeCommand (int i){
commands.add(i,command);
}
//得代執行命令
public void action(){
for(Iterator it = list.iterator();it.hasNext();){
Command command = Command) it.next();
Command. execute();
}
}
……………
//還可以有豐富的redo和undo操作;(當然一些都給基於命令類提供的相應方法)
}

//抽象命令
abstract class Command
{
abstract public void execute();
abstract public void unexecute();
abstract public void reexecute();
//一般有這樣這個方法,根據需要可以增刪
}

// 具體的命令類1:寫作命令,選擇一個作者(Author類例項物件),讓他寫作(呼叫它的write方法)寫作的物件是書(Book的例項物件)形成了一個寫作的命令,寫作的物件是Book的例項
public class WriteCommand implement Command
{
Author author; //執行者
Book book; //要執行的物件
public WriteCommand (Author author,Book book) {
this. author = author;
this. book = book;
}
// 在這裡執行要執行的操作
public override void Execute()
{
author.write (book);
}
}

// 具體的命令類2: 出版命令,選擇一個出版社(publisher類例項物件),讓他出版書(呼叫它的publisherBook方法)出版的物件是書(Book的例項物件)形成了一個出版的命令
public class PublishCommand implement Command
{
Publisher publisher;
Book book;
public PublishCommand (Publisher publisher) {
this. publisher = publisher;
this. book = book;
}
// Methods
public override void Execute()
{
publisher. publisherBook(book);
}
}

// Publisher和Author類為執行者


這樣我們的客戶端程式碼就可以這樣寫:
//如果我要出一本書
//一本空白的書
Book book = new Book();
//先找一個作者和出版社
Author author = new Author();
Publisher publisher = new Publisher ();
//產生命令集合
Command writeCommand = new WriteCommand (author,book);
Command publishCommand = new PublishCommand(publisher,book);
List commands = new List ();
Commands.add(writeCommand);
//找個呼叫者,把命令給它,讓他來根據命令協調工作
Invoker invoker = new invoker();
Invoker.setCommands(commands);
public void addCommand (Command command,int i){
commands.add(i,command);
}
invoker.action();

特點:
1》 分佈登記統一執行:
在作程式時,經常碰到一些需求,先註冊一些操作,並不馬上執行,等最終確定後統一執行。如一個具體的例子:使用者定製自己的報表,可以訂閱餅,柱,折線,曲線圖,客戶選擇相應的報表組合,這樣對應一個命令集合,在沒確定之前使用者可以增刪這些報表(命令),等最終確定統一交給呼叫者根據命令執行,生成組合報表。實現了命令分佈提出,確定後統一執行的功能。

2》形如流水線操作:還是出書的例子
//先是一本空白的書:
Book book = new Book();
//找幾個作者
Author author1 = new Author();
Author author2 = new Author();
//把寫1,2章的名類分別給這兩個作者
Command writeCommand = new Write1Command (author1,book);
Command writeCommand = new Write2Command (author2,book);
List commands = new List ();
Commands.add(writeCommand);
//呼叫者
Invoker invoker = new invoker();
Invoker.setCommands(commands);
//流水寫書
invoker.action()
實際上在aciton這一方法中,invoker按照命令,讓兩個作者流水寫作這本書。(類似一個書的流水線加工工廠)
這樣我們的書就被流水加工成功(當然這本書只有兩章)

這樣就給了我們一種系統設計的框架,
模型+工具+命令
客戶端產生命令,命令呼叫工具操作模型。
Book 相當於模型
Author 相當於和多工具類中的一個
Command 命令

3》系統需要支援命令的撤消(undo)。提供redo()方法
我們可以和容易的加入undo和redo,這個不難理解

4》在Invoker中我們可以實現跟蹤,和日誌。

5》當系統需要為某項複製增加形的功能的時候,命令模式使新的功能(表現為一種命令)很容易地被加入到服務種裡。
命令聯絡了工具類即執行類和系統邏輯,

簡化/變化的命令模式:
命令模式的角色比較多,在實際應用種我們可以根據所需要的功能和不需要的功能加以簡化。

1》去掉 呼叫者
產生命令集合後,我們可以直接在client中迭代執行執行操作
2》 變化 呼叫者 成為 跟蹤者
//呼叫者
public class Invoker{
List commands; //已經執行完畢的命令集合
public void addCommand (Command command,int i){
commands.add(i,command);
}
public void action(Command command){
//執行操作
command. execute();
//
commands.add(command);
}
}
……………
//還可以有豐富的redo和undo操作;(當然一些都給基於命令類提供的相應方法)
}
這樣這個類就記錄了所有執行過的操作。

3》去掉 命令 用map替代
我們完全可以用map代替命令,這樣無需定義各種命令類
我們改進例子
Author author = new Author();
Publisher publisher = new Publisher ();
Map m = new HashMap;
m.put(author, write);
m.put(author, publisherBook);
在Invoker的action方法:
得代map
運用java反射來呼叫方法;

4》去掉執行者:
直接在命令中(execute方法種)加業務邏輯。這樣只適合於簡單的小的系統.

其他要說的內容
1》 將某些引數傳給某個方發的方式很多,除了當作方法的引數外還可以當作類的成員便倆變數傳入:
這就為命令的抽象帶來了極大的方便
abstract class Command
{
abstract public void execute();
}
當我們已經有了執行者(類Test)方法execute(args1,args2 ….argsn)
我們不必向Command加入execute(args1,args2 ….argsn)抽象方法,在說即使加了,在我們迭代的時候也無法判斷或十分不容易判斷哪個命令呼叫哪個execute方法。
那麼我們可以這樣
class ConcreteCommand : Command
{
Test test;
args1
args2
…..
argsn
public override void Execute()
{
test. execute (args1,args2 ….argsn);
}
}
2》 在想跟蹤操作的時候,一般為每一個操作物件分配一個呼叫者,操作物件在呼叫者中設定。(可以抽象出一個總的呼叫者,來協調呼叫每一個具體的呼叫者)
3》 命令的抽象粒度我覺得是要注意的。
4》 理解思想,不要機械的照搬。消化成自己的,加以靈活的運用和創造在是根本出路。
所謂命令模式的根本思想就是在 先形成命令,在根據命令執行。

相關文章