命令模式算是设计模式中比较简单的,最常见的例子是工作任务安排下来进行编程,如果工作任务不需要完成,我们可以取消我们之前完成的代码,也可以理解为回滚撤销操作。这里面涉及到命令模式中的两个对象,一个是动作实现者,一个是行为请求者,我们可以将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(@"");
测试:
关于命令模式实现的比较简单,NSUndoManger算是命令模式的典型应用,在一些线程池,工作队列中,我们只需要将具体的执行的任务包装成命令,当任务可以用的时候执行里面的execute方法,在日志和版本控制系统中回滚,我们会回到之前的稳定的版本,取代当前不能工作的版本也可以理解为命令模式在工程实践中的应用。