命令模式算是设计模式中比较简单的,最常见的例子是工作任务安排下来进行编程,如果工作任务不需要完成,我们可以取消我们之前完成的代码,也可以理解为回滚撤销操作。这里面涉及到命令模式中的两个对象,一个是动作实现者,一个是行为请求者,我们可以将Boss理解为行为请求者,程序员理解为实现者,命令模式中我们通过调用者实现两者之间的解耦,生活中我们通过技术管理部门将老板和程序员隔离。我们有时候会遇到老板认为新版设计实现不如上一版,业务发生变化和开发效率的问题会随时进行任务的调整,虽然你有的时候很不情愿,但是还是会发生取消完成的任务,跟原来保持不变。
基础知识
先来看一下命令模式的UML类图:
Client:客户端,命令发送者;
Receiver:接收者,行为实现者;
Command:命令基类,定义基础的命令方法;
ConcreteCommand:命令子类,每个命令子类会关联一个Receiver,实现具体的任务;
Invoker:调用者,负责执行打包过的命令对象;
功能实现
我们可以先来定义Command类:
1
2
3
4
5
6
7
8
9
10
11
12
|
@protocol CommandProtocal <NSObject>
@optional
-(
void
)excute;
@optional
-(
void
)undo;
@end
@
interface
Command : NSObject<CommandProtocal>
@end
|
CarOnCommand类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@
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实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@
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类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@
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
|
1
|
<span style=
"font-family: 'Microsoft YaHei'; font-size: 14px;"
>DoorShutCommand</span>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@
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调用者的定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@
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的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
@
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
|
客户端调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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方法,在日志和版本控制系统中回滚,我们会回到之前的稳定的版本,取代当前不能工作的版本也可以理解为命令模式在工程实践中的应用。
本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/5108985.html,如需转载请自行联系原作者