命令(Command)模式
:又稱Action模式或者Transaction模式。它屬于對象的行為模式。命令模式把一個請求或者操作封裝到一個對象中。命令模式允許系統使用不同的請求把客戶端參數化,對請求排隊或者記錄請求日志,可以提供命令的撤銷和撤銷功能。
GoF命令模式結構圖如下:
抽象命令(Command)角色
:聲明執行操作的接口。
具體命令(ConcreteCommand)角色
:將一個接收者對象綁定到一個動作上。調用接收者相應的操作,以實現Execute方法。
客戶端(Client)角色
:創建一個命令對象并設定它的接收者。
請求者(Invoker)角色
:負責調用命令對象的執行請求;
接收者(Receiver)角色
:負責具體實施和執行一個請求相關的操作。任何一個類都可以作為一個接收者。
上面模型的模擬代碼如下:
- package ?command;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-20下午7:39:48 ?
- ?*描述:接收者角色 ?
- ?*/ ??
- public ? class ?Receiver?{??
- ??
- ???? public ?Receiver()?{??
- ???????? super ();??
- ????}??
- ??
- ???? /** ?
- ?????*? ?
- ?????*作者:alaric ?
- ?????*時間:2013-8-20下午7:40:00 ?
- ?????*描述:行動方法 ?
- ?????*/ ??
- ???? public ? void ?action(){??
- ????????System.out.println( "接收者接到命令,開始行動" );??
- ????}??
- }??
- package ?command;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-20下午7:36:51 ?
- ?*描述:抽象命令角色 ?
- ?*/ ??
- public ? interface ?Command?{??
- ??
- ???? /** ?
- ?????*? ?
- ?????*作者:alaric ?
- ?????*時間:2013-8-20下午7:36:40 ?
- ?????*描述:執行方法 ?
- ?????*/ ??
- ???? public ? void ?execute();??
- }??
- package ?command;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-20下午7:37:10 ?
- ?*描述:具體命令角色 ?
- ?*/ ??
- public ? class ?ConcreteCommand? implements ?Command?{??
- ??
- ???? private ?Receiver?receiver;??
- ??????
- ??????
- ???? public ?ConcreteCommand(Receiver?receiver)?{??
- ???????? super ();??
- ???????? this .receiver?=?receiver;??
- ????}??
- ??
- ??
- ???? @Override ??
- ???? public ? void ?execute()?{??
- ??????????
- ????????receiver.action();??
- ??????????
- ????}??
- ??????
- ??
- }??
- package ?command;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-20下午7:41:07 ?
- ?*描述: ?
- ?*/ ??
- public ? class ?Invoker?{??
- ??
- ???? private ?Command?command;??
- ??
- ???? public ?Invoker(Command?command)?{??
- ???????? super ();??
- ???????? this .command?=?command;??
- ????}??
- ??????
- ???? public ? void ?action(){??
- ????????command.execute();??
- ????}??
- }??
- package ?command;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-20下午7:33:51 ?
- ?*描述:客戶端角色 ?
- ?*/ ??
- public ? class ?Client?{??
- ??
- ???? /** ?
- ?????*作者:alaric ?
- ?????*時間:2013-8-20下午7:33:44 ?
- ?????*描述: ?
- ?????*/ ??
- ???? public ? static ? void ?main(String[]?args)?{??
- ????????Receiver?receiver?=? new ?Receiver();??
- ????????Command?command?=? new ?ConcreteCommand(receiver);??
- ????????Invoker?invoker?=? new ?Invoker(command);??
- ????????invoker.action();??
- ????}??
- ??
- }??
1、命令模式使新的命令在不改變現有結構代碼的情況下很容易被加入到系統里;
2、允許接收請求的一方決定是否否決請求;
3、能較容易地設計一個命令隊列;
4、可以容易地實現對請求的Undo和Redo操作;
5、在需要的情況下以較容易地將命令記入日志。
?
在講門面模式的時候曾經提過一個例子,我們小時玩過投幣的那種游戲機,一個方向操作桿,四個動作按鈕,在一個操作面板上,封裝了復雜的邏輯在機器內部,提供簡單的操作界面,是一個門面的例子,然而每個操作發出一個命令,來控制游戲人物的運動和各種動作。方向操作桿是一個移動的命令,傳入移動的方向和距離作為參數,還有出拳按鍵發出出拳命令,腳踢按鍵發出腳踢的命令,那還有組合操作命令,比如下踢腿(操作桿向下和踢腳按鈕按下)。現在我們用命令模式來模擬這個場景。類的模型圖如下:

?如上圖所示:Client相當于小時候的我們,Control相關于控制執行器,我們可以控制踢(KickCommand)、打(FistCommand)、移動(MoveCommand),這些命令的最終實現者也是接收者是游戲機(GameMachine)。
代碼如下:
- package ?command.example;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-21上午7:15:53 ?
- ?*描述:接收者 ?
- ?*/ ??
- public ? class ?GameMachine?{??
- ??
- ???? public ? void ?fist()?{??
- ????????System.out.println( "出拳" );??
- ????}??
- ??????
- ???? public ? void ?kick()?{??
- ????????System.out.println( "出腳" );??
- ????}??
- ??????
- ???? public ? void ?move(String?direction){??
- ????????System.out.println( "向" +direction+ "移動" );??
- ????}??
- ??
- }??
- package ?command.example;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-20下午10:20:35 ?
- ?*描述:命令接口 ?
- ?*/ ??
- public ? interface ?Command?{??
- ??
- ???? //執行方法 ??
- ???? public ? void ?execute();??
- ??????
- ???? //這里還可以加入撤銷方法,回滾方法等 ??
- }??
- package ?command.example;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-21上午7:17:02 ?
- ?*描述:拳打 ?
- ?*/ ??
- public ? class ?FistCommand? implements ?Command?{??
- ???? private ?GameMachine?machine;??
- ??????
- ??????
- ??????
- ???? public ?FistCommand(GameMachine?machine)?{??
- ???????? super ();??
- ???????? this .machine?=?machine;??
- ????}??
- ??
- ??
- ??
- ???? @Override ??
- ???? public ? void ?execute()?{??
- ????????machine.fist();??
- ????}??
- ??
- ??
- }??
- package ?command.example;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-21上午7:42:21 ?
- ?*描述:腳踢命令 ?
- ?*/ ??
- public ? class ?KickCommand? implements ?Command?{??
- ???? private ?GameMachine?machine;??
- ??????
- ???? public ?KickCommand(GameMachine?machine)?{??
- ???????? super ();??
- ???????? this .machine?=?machine;??
- ????}??
- ??
- ???? @Override ??
- ???? public ? void ?execute()?{??
- ????????machine.kick();??
- ????}??
- ??
- }??
- package ?command.example;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-21上午7:17:02 ?
- ?*描述:移動命令 ?
- ?*/ ??
- public ? class ?MoveCommand? implements ?Command?{??
- ???? private ?GameMachine?machine;??
- ???? private ?String?direction;??
- ??????
- ??????
- ???? public ?MoveCommand(GameMachine?machine,String?direction)?{??
- ???????? super ();??
- ???????? this .machine?=?machine;??
- ???????? this .direction?=?direction;??
- ????}??
- ??
- ??
- ??
- ???? @Override ??
- ???? public ? void ?execute()?{??
- ????????machine.move(direction);??
- ????}??
- ??
- ??????
- ??
- }??
- package ?command.example;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-21上午7:43:14 ?
- ?*描述:控制類 ?
- ?*/ ??
- public ? class ?Control?{??
- ??????
- ???? private ?Command?fistCommand;??
- ???? private ?Command?kickCommand;??
- ???? private ?Command?moveCommand;??
- ??????
- ???? public ?Control(Command?fistCommand,?Command?kickCommand,?Command?moveCommand)?{??
- ???????? super ();??
- ???????? this .fistCommand?=?fistCommand;??
- ???????? this .kickCommand?=?kickCommand;??
- ???????? this .moveCommand?=?moveCommand;??
- ????}??
- ??????
- ???? public ? void ?fist(){??
- ????????fistCommand.execute();??
- ????}??
- ??????
- ???? public ? void ?kick(){??
- ????????kickCommand.execute();??
- ????}??
- ??????
- ???? public ? void ?move(){??
- ????????moveCommand.execute();??
- ????}??
- ??
- }??
- package ?command.example;??
- /** ?
- ?*? ?
- ?*作者:alaric ?
- ?*時間:2013-8-20下午9:26:42 ?
- ?*描述:客戶端角色 ?
- ?*/ ??
- public ? class ?Client?{??
- ??
- ???? /** ?
- ?????*作者:alaric ?
- ?????*時間:2013-8-20下午9:26:36 ?
- ?????*描述:測試 ?
- ?????*/ ??
- ???? public ? static ? void ?main(String[]?args)?{??
- ??
- ????????GameMachine?machine?=? new ?GameMachine();??
- ????????Command?fistCommand?=? new ?FistCommand(machine);??
- ????????Command?kickCommand?=? new ?KickCommand(machine);??
- ????????Command?moveCommand?=? new ?MoveCommand(machine,? "左" );??
- ??????????
- ????????Control?control?=? new ?Control(fistCommand,?kickCommand,?moveCommand);??
- ????????control.fist();??
- ????????control.kick();??
- ????????control.move();??
- ??????????
- ???????? //其實在不同命令模式的情況下就是下面這樣直接調用, ??
- ???????? //就會讓調用者和實際命令執行者緊緊耦合在一起,還有一個好處 ??
- ???????? //就是可以在 ??
- ???????? //machine.fist(); ??
- ???????? //machine.kick(); ??
- ???????? //machine.move("左"); ??
- ????}??
- ??
- }??
?運行結果如下:
出拳
出腳
向左移動
?
通過上面代碼可以看出,本來客戶端可以直接調用接收者來執行動作的,現在在中間引入了命令,這些命令由調用者(Invoker這里是Control)來調用,從而對客戶端和命令接收者解耦了,增加了命令后,使得命令除了execute方法外,可以插入很多其它動作,比如redo,undo,或者記錄日志等。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
