命令模式
意图:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
通过被称为Command的类封装了对目标对象的调用行为以及调用参数。
在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。
但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作Command类。
整个调用过程比较复杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
命令模式.jpg角色和职责
-
Command (抽象看病、做饭菜)
Command命令的抽象类,声明执行操作的接口 -
ConcreteCommand(看具体的病、做具体的饭菜)
Command的具体实现类
将一个接收者对象绑定于一个动作
调用接收者相应的操作,以实现excute -
Receiver (医生、厨师)
需要被调用的目标对象
知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者 -
Invoker (护士、服务员)
通过Invoker执行Command对象
要求该命令执行这个请求 -
Client (客户端)
创建一个具体命令对象并设定它的接收者
代码示例1
医生直接看病
//技术推演
#import <Foundation/Foundation.h>
@interface Doctor : NSObject
@end
@implementation Doctor
- (void)treatEye {
NSLog(@"医生治疗眼睛");
}
- (void)treatNose {
NSLog(@"医生治疗鼻子");
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
//医生直接看病 实质:Receiver->action()
Doctor *doctor = [[Doctor alloc] init];
[doctor treatEye];
[doctor treatNose];
//医生和客户端耦合度太高
}
return 0;
}
/*
医生治疗眼睛
医生治疗鼻子
*/
代码示例2
医生通过命令看病
//技术推演
#import <Foundation/Foundation.h>
@interface Doctor : NSObject
@end
@implementation Doctor
- (void)treatEye {
NSLog(@"医生治疗眼睛");
}
- (void)treatNose {
NSLog(@"医生治疗鼻子");
}
@end
//治疗眼睛命令
@interface CommandTreatEye : NSObject
@property (nonatomic, strong) Doctor *doctor;
@end
@implementation CommandTreatEye
//命令持有医生,通过代码注入的方式将医生注入到治疗眼睛命令中,也可以通过setter方法
- (instancetype)initWithDoctor:(Doctor *)doctor {
if (self = [super init]) {
self.doctor = doctor;
}
return self;
}
- (void)treat {
[self.doctor treatEye];
}
@end
//治疗鼻子命令
@interface CommandTreatNose : NSObject
@property (nonatomic, strong) Doctor *doctor;
@end
@implementation CommandTreatNose
- (instancetype)initWithDoctor:(Doctor *)doctor {
if (self = [super init]) {
self.doctor = doctor;
}
return self;
}
- (void)treat {
[self.doctor treatNose];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
//通过一个命令,命令执行让医生看病 实质:Command.doctor->action
Doctor *doctor = [[Doctor alloc] init];
CommandTreatEye *commandTreatEye = [[CommandTreatEye alloc] initWithDoctor:doctor];
[commandTreatEye treat];
CommandTreatNose *commandTreatNose = [[CommandTreatNose alloc] initWithDoctor:doctor];
[commandTreatNose treat];
}
return 0;
}
/*
医生治疗眼睛
医生治疗鼻子
*/
代码示例3
实现客户端和命令解耦合
//技术推演
#import <Foundation/Foundation.h>
//医生 请求接收者 Receiver
@interface Doctor : NSObject
@end
@implementation Doctor
- (void)treatEye {
NSLog(@"医生治疗眼睛");
}
- (void)treatNose {
NSLog(@"医生治疗鼻子");
}
@end
//请求发起者 面向抽象类编程
@interface Command : NSObject
@property (nonatomic, strong) Doctor *doctor;
@end
@implementation Command
- (void)treat {
}
@end
//治疗眼睛命令 ConcreteCommand
@interface CommandTreatEye : Command
@end
@implementation CommandTreatEye
- (instancetype)initWithDoctor:(Doctor *)doctor {
if (self = [super init]) {
self.doctor = doctor;
}
return self;
}
- (void)treat {
[self.doctor treatEye];
}
@end
//治疗鼻子命令 ConcreteCommand
@interface CommandTreatNose : Command
@end
@implementation CommandTreatNose
- (instancetype)initWithDoctor:(Doctor *)doctor {
if (self = [super init]) {
self.doctor = doctor;
}
return self;
}
- (void)treat {
[self.doctor treatNose];
}
@end
//护士 请求发起者 Invoker
@interface Nurse : NSObject
@property (nonatomic, strong) Command *command;
@end
@implementation Nurse
- (instancetype)initWithCommand:(Command *)command {
if (self = [super init]) {
self.command = command;
}
return self;
}
//提交命令,让医生看病
- (void)submittedCase {
[self.command treat];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Doctor *doctor = [[Doctor alloc] init];
Command *command = [[CommandTreatEye alloc] initWithDoctor:doctor];
//Command *command = [[CommandTreatNose alloc] initWithDoctor:doctor];
//实质:Invoke.command.doctor->action()
Nurse *nurse = [[Nurse alloc] initWithCommand:command];
[nurse submittedCase]; //护士提交命令,让医生看病
}
return 0;
}
/*
医生治疗眼睛
//医生治疗鼻子
*/
代码示例4
实现请求排队,批量下单
//技术推演
#import <Foundation/Foundation.h>
//医生 请求接收者 Receiver
@interface Doctor : NSObject
@end
@implementation Doctor
- (void)treatEye {
NSLog(@"医生治疗眼睛");
}
- (void)treatNose {
NSLog(@"医生治疗鼻子");
}
@end
//请求发起者 面向抽象类编程
@interface Command : NSObject
@property (nonatomic, strong) Doctor *doctor;
@end
@implementation Command
- (void)treat {
}
@end
//治疗眼睛命令 ConcreteCommand
@interface CommandTreatEye : Command
@end
@implementation CommandTreatEye
- (instancetype)initWithDoctor:(Doctor *)doctor {
if (self = [super init]) {
self.doctor = doctor;
}
return self;
}
- (void)treat {
[self.doctor treatEye];
}
@end
//治疗鼻子命令 ConcreteCommand
@interface CommandTreatNose : Command
@end
@implementation CommandTreatNose
- (instancetype)initWithDoctor:(Doctor *)doctor {
if (self = [super init]) {
self.doctor = doctor;
}
return self;
}
- (void)treat {
[self.doctor treatNose];
}
@end
//护士长 请求发起者 批量下达命令
@interface HeadNurse : NSObject
@property (nonatomic, strong) Command *command;
@property (nonatomic, strong) NSMutableArray<Command *> *commands;
@end
@implementation HeadNurse
- (void)setCommand:(Command *)command {
[self.commands addObject:command];
}
//提交命令,让医生看病
- (void)submittedCase {
for (Command *command in self.commands) {
[command treat];
}
}
- (NSMutableArray<Command *> *)commands {
if (!_commands) {
_commands = [NSMutableArray array];
}
return _commands;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Doctor *doctor = [[Doctor alloc] init];
Command *command1 = [[CommandTreatEye alloc] initWithDoctor:doctor];
Command *command2 = [[CommandTreatNose alloc] initWithDoctor:doctor];
//实质:Invoke.command.doctor->action()
HeadNurse *hNurse = [[HeadNurse alloc] init];
//setter方法收集命令
hNurse.command = command1;
hNurse.command = command2;
[hNurse submittedCase];
}
return 0;
}
/*
医生治疗眼睛
医生治疗鼻子
*/
用处
上述看病的例子,护士长收集看眼睛的、看鼻子的命令,然后让医生看病。类似的还有很多,如点餐,客户到餐馆点份炒饼、疙瘩汤等,告诉服务员,服务员将客户的请求下达给厨师,厨师做饭菜。这里的点餐就相当于“命令”,服务员就相当于“调用者”,厨师相当于“接收者”...
命令模式的实质就是把动作(方法)分解,分解成发送者和接收者。
命令模式的主要应用场景就是用来控制命令的执行。落实到编码就是借助命令模式将函数(方法)封装成对象,这样就可以实现把函数像对象一样使用。
优点
- 行为参数化,降低系统的耦合度
- 新的命令可以很容易添加到系统中
缺点
使用命令模式可能回导致某些系统有过多的具体命令类。因为针对每一个对请求接收者的调用操作都需要设计一个具体命令类,因此,在某些系统中可能需要提供大量的具体命令类,这将影响命令模式的使用。
网友评论