iOS开发-命令模式

命令模式算是设计模式中比较简单的,最常见的例子是工作任务安排下来进行编程,如果工作任务不需要完成,我们可以取消我们之前完成的代码,也可以理解为回滚撤销操作。这里面涉及到命令模式中的两个对象,一个是动作实现者,一个是行为请求者,我们可以将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
DoorShutCommand
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方法,在日志和版本控制系统中回滚,我们会回到之前的稳定的版本,取代当前不能工作的版本也可以理解为命令模式在工程实践中的应用。

 

posted @   Fly_Elephant  阅读(2113)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述
历史上的今天:
2015-01-10 Objective-C-Category类别
2015-01-10 Objective-C面向对象之实现类
点击右上角即可分享
微信分享提示