命令模式:将请求封装成对象,以便使用不同的请求,队列,或日志,来参数化其他对象。命令模式也支持可撤销的操作。
命令模式是行为型模式之一。命令模式的核心就是将方法调用封装起来。通过封装方法调用,我们可以将运算块包装成形。调用运算块的对象不需要关心运算块是怎么运行的。只需要知道如何使用包装好的方法来完成它即可。
并且其中我们还可以做一些聪明的事,比如说记录日志,或者利用封装实现撤销操作。
这里封装的目的就是简化操作,比如说如何点亮一盏灯?作为核心开发人员需要了解控制和灯的相关接口和协议,普通人只需知道按下开关灯就亮了。命令模式就是将这些中间过程统一封装在命令中,然后只提供开/关命令。
下面是命令模式具体类图
命令模式
举个栗子(Head first上的栗子很有代表性,我不打算找其他的栗子,就把哪个智能遥控器的栗子搬过来,稍微简化下)
有个上游的厂商生产一款智能的遥控器,遥控器可以连接电灯,空调,电视或者更多其他的电子设备,遥控上面只有两种按钮一种是开启,一个是取消。每个按钮可以对应于任何设备的任何一个功能。
我们如何让遥控和设备对接。让它能控制对应的设备,并且可以方便后续扩展。
遥控器
第一排的左边按钮就开启电视,按第一排右边的按钮是还原。
第二排的左边按钮是调高空调的温度,右边的按钮是还原。
....
命令协议
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol Command <NSObject>
-(void)excute;
-(void)undo;
@end
NS_ASSUME_NONNULL_END
下游厂商的设备(电灯)
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Light : NSObject
-(void)on;
-(void)off;
@end
NS_ASSUME_NONNULL_END
下游厂商的设备(空调)
#import "AirCondition.h"
@interface AirCondition()
@property (nonatomic ,strong)NSMutableArray * temprature_in_type;
@end
@implementation AirCondition
-(instancetype)init {
if (self = [super init]) {
_temprature_in_type = [NSMutableArray arrayWithObjects:@(26),@(26),@(26),@(26), nil];
_temperature = [_temprature_in_type[_type] integerValue];
}return self;
}
-(void)changeType {
if (_type == AirCondition_Dust_Removal){
_type = AirCondition_Refrigeration;
_temperature = [_temprature_in_type[_type] integerValue];
} else {
_type ++;
_temperature = [_temprature_in_type[_type] integerValue];
}
}
-(void)reduceTemperature {
_temperature --;
_temprature_in_type[_type] = @(_temperature);
}
-(void)increaseTemperature {
_temperature ++;
_temprature_in_type[_type] = @(_temperature);
}
-(void)on {
NSString * type ;
switch (_type) {
case AirCondition_Refrigeration:
type = @"制冷模式";
break;
case AirCondition_Heating:
type = @"制热模式";
break;
case AirCondition_Dehumidification:
type = @"除湿模式";
break;
case AirCondition_Dust_Removal:
type = @"除尘模式";
break;
}
NSLog(@"空调开启了,当前模式为%@,设定温度为%ld℃",type,_temperature);
}
-(void)off {
NSLog(@"空调关闭了");
}
@end
灯泡亮起的命令
#import "LightOnCommand.h"
#import "Light.h"
@interface LightOnCommand ()
@property (nonatomic ,strong)Light * light;
@end
@implementation LightOnCommand
-(instancetype)initWithLight:(Light *)light {
if (self = [super init]) {
_light = light;
}return self;
}
-(void)excute {
[_light on];
}
- (void)undo {
[_light off];
}
@end
灯泡熄灭的命令
#import "LightOffCommand.h"
#import "Light.h"
@interface LightOffCommand ()
@property (nonatomic ,strong)Light * light;
@end
@implementation LightOffCommand
-(instancetype)initWithLight:(Light *)light {
if (self = [super init]) {
_light = light;
}return self;
}
-(void)excute {
[_light off];
}
- (void)undo {
[_light on];
}
@end
空调开启的命令
#import "AirConditionOnCommand.h"
#import "AirCondition.h"
@interface AirConditionOnCommand ()
@property (nonatomic ,strong)AirCondition * condition;
@end
@implementation AirConditionOnCommand
-(instancetype)initWithAirCondition:(AirCondition *)condition {
if (self = [super init]) {
_condition = condition;
}return self;
}
- (void)excute {
[_condition on];
}
- (void)undo {
[_condition off];
}
@end
空调关闭的命令
#import "AirConditionOffCommand.h"
#import "AirCondition.h"
@interface AirConditionOffCommand ()
@property (nonatomic ,strong)AirCondition * condition;
@end
@implementation AirConditionOffCommand
-(instancetype)initWithAirCondition:(AirCondition *)condition {
if (self = [super init]) {
_condition = condition;
}return self;
}
- (void)excute {
[_condition off];
}
- (void)undo {
[_condition on];
}
@end
空调状态切换的命令
#import "AirConditionChangeTypeCommand.h"
#import "AirCondition.h"
@interface AirConditionChangeTypeCommand ()
@property (nonatomic ,strong)AirCondition * condition;
@property (nonatomic ,assign)AirConditionType type;
@end
@implementation AirConditionChangeTypeCommand
-(instancetype)initWithAirCondition:(AirCondition *)condition {
if (self = [super init]) {
_condition = condition;
}return self;
}
- (void)excute {
_type = _condition.type;
[_condition changeType];
}
- (void)undo {
_condition.type = _type;
}
@end
空调温度降低的命令
#import "AirConditionReduceTemperatureCommand.h"
#import "AirCondition.h"
@interface AirConditionReduceTemperatureCommand ()
@property (nonatomic ,strong)AirCondition * condition;
@end
@implementation AirConditionReduceTemperatureCommand
-(instancetype)initWithAirCondition:(AirCondition *)condition {
if (self = [super init]) {
_condition = condition;
}return self;
}
- (void)excute {
[_condition reduceTemperature];
}
- (void)undo {
[_condition increaseTemperature];
}
@end
空调增温的命令
#import "AirConditionIncreaseTemperatureCommand.h"
#import "AirCondition.h"
@interface AirConditionIncreaseTemperatureCommand()
@property (nonatomic ,strong)AirCondition * condition;
@end
@implementation AirConditionIncreaseTemperatureCommand
-(instancetype)initWithAirCondition:(AirCondition *)condition {
if (self = [super init]) {
_condition = condition;
}return self;
}
- (void)excute {
[_condition increaseTemperature];
}
- (void)undo {
[_condition reduceTemperature];
}
@end
调用者(Invoker)这里的调用者就是遥控器
#import "RemoteControl.h"
#import "NoCommand.h"
@interface RemoteControl ()
@property (nonatomic ,strong)NSMutableArray * onCommands;
@property (nonatomic ,strong)NSMutableArray * offCommands;
@property (nonatomic ,strong)NSMutableArray * undoCommands;
@end
@implementation RemoteControl
-(instancetype)initWithControlSize:(NSInteger)size {
if (self = [super init]) {
_onCommands = [NSMutableArray arrayWithCapacity:size];
_offCommands = [NSMutableArray arrayWithCapacity:size];
_undoCommands = [NSMutableArray array];
NoCommand * command = [[NoCommand alloc] init];
for (int i = 0 ; i < size ; i++) {
_onCommands[i] = command;
_offCommands[i] = command;
}
}return self;
}
-(void)setOnCommand:(id<Command>)onCommand offCommand:(id<Command>)offCommand atIndex:(NSInteger)index {
_onCommands[index] = onCommand;
_offCommands[index] = offCommand;
}
-(void)onButtonPushedAtIndex:(NSInteger)index {
if (index > _onCommands.count - 1) return ;
if (index < 0) return;
id<Command> command = _onCommands[index];
[command excute];
[_undoCommands addObject:command];
}
-(void)offButtonPushedAtIndex:(NSInteger)index {
if (index > _onCommands.count - 1) return ;
if (index < 0) return;
id<Command> command = _offCommands[index];
[command excute];
[_undoCommands addObject:command];
}
-(void)undoButtonPushed {
if (_undoCommands.count <= 0) return ;
id<Command> command = _undoCommands.lastObject;
[_undoCommands removeLastObject];
[command undo];
}
@end
具体使用
#import <Foundation/Foundation.h>
#import "LightOnCommand.h"
#import "LightOffCommand.h"
#import "AirConditionOnCommand.h"
#import "AirConditionOffCommand.h"
#import "AirConditionChangeTypeCommand.h"
#import "AirConditionReduceTemperatureCommand.h"
#import "AirConditionIncreaseTemperatureCommand.h"
#import "RemoteControl.h"
#import "Light.h"
#import "AirCondition.h"
//客户
int main(int argc, const char * argv[]) {
@autoreleasepool {
//接收者
Light * light = [[Light alloc] init];
AirCondition * condition = [[AirCondition alloc] init];
//命令
//开关
LightOnCommand * lightOn = [[LightOnCommand alloc] initWithLight:light];
LightOffCommand * lightOff = [[LightOffCommand alloc] initWithLight:light];
//空调开关
AirConditionOnCommand * airOn = [[AirConditionOnCommand alloc] initWithAirCondition:condition];
AirConditionOffCommand * airOff = [[AirConditionOffCommand alloc] initWithAirCondition:condition];
//空调控制
AirConditionChangeTypeCommand * airType = [[AirConditionChangeTypeCommand alloc] initWithAirCondition:condition];
//空调温度
AirConditionReduceTemperatureCommand * airReduTemp = [[AirConditionReduceTemperatureCommand alloc] initWithAirCondition:condition];
AirConditionIncreaseTemperatureCommand * airIncrTemp = [[AirConditionIncreaseTemperatureCommand alloc] initWithAirCondition:condition];
//调用者
RemoteControl * control = [[RemoteControl alloc] initWithControlSize:5];
//添加command
[control setOnCommand:lightOn offCommand:lightOff atIndex:0];
[control setOnCommand:airOn offCommand:airOff atIndex:1];
[control setOnCommand:airType offCommand:airOff atIndex:2];
[control setOnCommand:airReduTemp offCommand:airOff atIndex:3];
[control setOnCommand:airIncrTemp offCommand:airOff atIndex:4];
[control onButtonPushedAtIndex:2];
[control onButtonPushedAtIndex:1];
}
return 0;
}
优点
将调用命令的对象和命令解耦
很容易添加新的命令
很容易取消旧的命令
可以将多个命令组合成一个命令
缺点
会导致系统具有过多的命令类













网友评论