命令模式算是設計模式中比較簡單的,最常見的例子是工作任務安排下來進行編程,如果工作任務不需要完成,我們可以取消我們之前完成的代碼,也可以理解為回滾撤銷操作。這里面涉及到命令模式中的兩個對象,一個是動作實現者,一個是行為請求者,我們可以將Boss理解為行為請求者,程序員理解為實現者,命令模式中我們通過調用者實現兩者之間的解耦,生活中我們通過技術管理部門將老板和程序員隔離。我們有時候會遇到老板認為新版設計實現不如上一版,業務發生變化和開發效率的問題會隨時進行任務的調整,雖然你有的時候很不情願,但是還是會發生取消完成的任務,跟原來保持不變。
基礎知識
先來看一下命令模式的UML類圖:
Client:客戶端,命令發送者;
Receiver:接收者,行為實現者;
Command:命令基類,定義基礎的命令方法;
ConcreteCommand:命令子類,每個命令子類會關聯一個Receiver,實現具體的任務;
Invoker:調用者,負責執行打包過的命令對象;
功能實現
我們可以先來定義Command類:
@protocol CommandProtocal <NSObject> @optional -(void)excute; @optional -(void)undo; @end @interface Command : NSObject<CommandProtocal> @end
CarOnCommand類:
@interface CarOnCommand(){ Car *car; } @end @implementation CarOnCommand -(instancetype)initWithCar:(Car *)myCar{ self=[super init]; if (self) { car=myCar; } return self; } -(void)excute{ [car on]; } -(void)undo{ [car off]; } @end
CarOffCommand實現:
@interface CarOffCommand(){ Car *car; } @end @implementation CarOffCommand -(instancetype)initWithCar:(Car *)myCar{ self=[super init]; if (self) { car=myCar; } return self; } -(void)excute{ [car off]; } -(void)undo{ [car on]; } @end
DoorOpenCommand類:
@interface DoorOpenCommand(){ Door *myDoor; } @end @implementation DoorOpenCommand -(instancetype)initWithDoor:(Door *)door{ self=[super init]; if (self) { myDoor=door; } return self; } -(void)excute{ [myDoor open]; } -(void)undo{ [myDoor shut]; } @end
DoorShutCommand
@interface DoorShutCommand(){ Door *myDoor; } @end @implementation DoorShutCommand -(instancetype)initWithDoor:(Door *)door{ self=[super init]; if (self) { myDoor=door; } return self; } -(void)excute{ [myDoor shut]; } -(void)undo{ [myDoor open]; } @end
這里需要提示一樣,因為每個命令都會有撤銷的功能,因為打開和關閉是兩個單獨的命令,不同對象的對象也是分開使用不同的命令,每個對象內部關於excute實現的過程會有不同~
Invoker調用者的定義:
@interface EleControl : NSObject -(instancetype)initWithCommandCount:(NSInteger)count; -(void)setupCommand:(NSInteger)index onCommand:(Command *)onCommand offCommand:(Command *)offCommand; -(void)controlPressedOn:(NSInteger)index; -(void)controlPressedOff:(NSInteger)index; -(void)controlPressedUndo; @end
Invoker的實現:
@interface EleControl(){ Command *undoCommand; } @property (strong,nonatomic) NSMutableArray *onCommands; @property (strong,nonatomic) NSMutableArray *offCommands; @end @implementation EleControl -(instancetype)initWithCommandCount:(NSInteger)count{ self=[super init]; if (self) { for (NSInteger i=0; i<count; i++) { [self.onCommands addObject:[NSNull null]]; [self.offCommands addObject:[NSNull null]]; } } return self; } -(void)setupCommand:(NSInteger)index onCommand:(Command *)onCommand offCommand:(Command *)offCommand{ self.onCommands[index]=onCommand; self.offCommands[index]=offCommand; } -(void)controlPressedOn:(NSInteger)index{ Command *cmd=[self.onCommands objectAtIndex:index]; [cmd excute]; undoCommand=cmd; } -(void)controlPressedOff:(NSInteger)index{ Command *cmd=[self.offCommands objectAtIndex:index]; [cmd excute]; undoCommand=cmd; } -(void)controlPressedUndo{ [undoCommand undo]; } #pragma mark getter and setter -(NSMutableArray *)onCommands{ if (!_onCommands) { _onCommands=[[NSMutableArray alloc]init]; } return _onCommands; } -(NSMutableArray *)offCommands{ if (!_offCommands) { _offCommands=[[NSMutableArray alloc]init]; } return _offCommands; } @end
客戶端調用:
Car *car=[[Car alloc]init]; Command *carOnCommand=[[CarOnCommand alloc]initWithCar:car]; Command *carOffCommand=[[CarOffCommand alloc]initWithCar:car]; Door *door=[[Door alloc]init]; Command *doorOpenCommand=[[DoorOpenCommand alloc]initWithDoor:door]; Command *doorShutCommand=[[DoorShutCommand alloc]initWithDoor:door]; EleControl *control=[[EleControl alloc]initWithCommandCount:2]; [control setupCommand:0 onCommand:carOnCommand offCommand:carOffCommand]; [control setupCommand:1 onCommand:doorOpenCommand offCommand:doorShutCommand]; [control controlPressedOn:0]; [control controlPressedOff:1]; [control controlPressedUndo]; NSLog(@"博客園-FlyElephant"); NSLog(@"http://www.cnblogs.com/xiaofeixiang/");
測試:
關於命令模式實現的比較簡單,NSUndoManger算是命令模式的典型應用,在一些線程池,工作隊列中,我們只需要將具體的執行的任務包裝成命令,當任務可以用的時候執行里面的execute方法,在日志和版本控制系統中回滾,我們會回到之前的穩定的版本,取代當前不能工作的版本也可以理解為命令模式在工程實踐中的應用。