电视机、遥控器与接收器之间的关系
- 遥控器与接收器并非必要的设备,比如手动调节电视机的音量也可以
- 接收器转换遥控器的信号
命令模式
在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)。命令的执行者和命令的发起者是解耦的,比如最后一个实例中的command的和view是没有直接关联,命令模式能执行回退,撤销,重做等操作,这是最大的用途
- Client:可以有多个实体,client即使没有receiver,自身也能操作。
- Receiver: 持有了client的引用,将遥控器的指令翻译成电视机能接收的,它的方法就是针对client的操作。
- CommandProtocol:所有对象必须遵循的规范。
- Command: 每个命令抽象成一个对象,且必须遵循命令协议。好比遥控器上的每个按钮。
- Invoker:单例,存储命令的地方。好比一个含有很多按钮的遥控器。
CommandProtocol
@protocol CommandProtocol <NSObject>
@required
//命令的执行
- (void)excute;
//与接收器绑定并设置参数
- (void)initWithReceiver:(Receiver *)receiver paramter:(id)paramter;
Invoker :
@interface Invoker : NSObject
//回退操作
- (void)rollBack;
//添加指令操作
- (void)addAndExcute:(id <CommandProtocol>)command;
@end
@interface Invoker ()
@property (nonatomic, strong) NSMutableArray *queue;
@end
@implementation Invoker
+ (instancetype)shareInstance {
static Invoker *shareInstanceValue = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
shareInstanceValue = [[Invoker alloc] init];
shareInstanceValue.queue = [NSMutableArray array];
});
return shareInstanceValue;
}
- (void)rollBack {
// todo
}
- (void)addAndExcute:(id <CommandProtocol>)command {
NSParameterAssert(command);
[self.queue addObject:command];
[command excute];
}
Receiver
@interface Receiver : NSObject
//被服务对象
@property (nonatomic, strong) id client;
//增加频道
- (void)addNum:(NSNumber *)num;
//减少频道
- (void)delNum:(NSNumber *)num;
@end
@implementation Receiver
- (void)addNum:(NSNumber *)num {
// todo
}
- (void)delNum:(NSNumber *)num {
// todo
}
@end
改变一个视图的明暗程度
ViewController
typedef enum : NSUInteger {
kAddButtonTag = 10, // 增加按钮枚举值
kDelButtonTag, // 减少按钮枚举值
kRolButtonTag, // 回退按钮枚举值
} ViewControllerEnumValue;
@interface ViewController ()
@property (nonatomic, strong) UIButton *addButton;
@property (nonatomic, strong) UIButton *delButton;
@property (nonatomic, strong) UIButton *rolButton;
@property (nonatomic, strong) Receiver *receiver;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 接收器
self.receiver = [[Receiver alloc] init];
self.receiver.clientView = self.view;
// 初始化按钮
[self initButtons];
}
- (void)buttonsEvent:(UIButton *)button {
if (button.tag == kAddButtonTag) {
NSLog(@"增加操作");
LighterCommond *commond = [[LighterCommond alloc] initWithReceiver:self.receiver paramter:0.1];
[[Invoker shareInstance] addAndExcute:commond];
} else if (button.tag == kDelButtonTag) {
NSLog(@"减少操作");
DarkerCommand *commond = [[DarkerCommand alloc] initWithReceiver:self.receiver paramter:0.1];
[[Invoker shareInstance] addAndExcute:commond];
} else if (button.tag == kRolButtonTag) {
NSLog(@"回退操作");
[[Invoker shareInstance] rollBack];
}
}
#pragma mark - 无关初始化
- (void)initButtons {
// delButton
self.delButton = [[UIButton alloc] initWithFrame:CGRectMake(10, 25, 30, 30)];
self.delButton.tag = kDelButtonTag;
self.delButton.layer.borderWidth = 1.f;
[self.delButton setTitle:@"-"
forState:UIControlStateNormal];
[self.delButton setTitleColor:[UIColor redColor]
forState:UIControlStateNormal];
[self.delButton addTarget:self
action:@selector(buttonsEvent:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.delButton];
// addButton
self.addButton = [[UIButton alloc] initWithFrame:CGRectMake(10 + 40, 25, 30, 30)];
self.addButton.tag = kAddButtonTag;
self.addButton.layer.borderWidth = 1.f;
[self.addButton setTitle:@"+"
forState:UIControlStateNormal];
[self.addButton setTitleColor:[UIColor redColor]
forState:UIControlStateNormal];
[self.addButton addTarget:self
action:@selector(buttonsEvent:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.addButton];
// rolButton
self.rolButton = [[UIButton alloc] initWithFrame:CGRectMake(10 + 80, 25, 90, 30)];
self.rolButton.tag = kRolButtonTag;
self.rolButton.layer.borderWidth = 1.f;
[self.rolButton setTitle:@"rollBack"
forState:UIControlStateNormal];
[self.rolButton setTitleColor:[UIColor redColor]
forState:UIControlStateNormal];
[self.rolButton addTarget:self
action:@selector(buttonsEvent:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.rolButton];
}
CommandProtocol
@protocol CommandProtocol <NSObject>
@required
//执行命令
- (void)excute;
//撤销命令
- (void)rollBackExcute;
@end
DarkerCommand
@interface DarkerCommand : NSObject <CommandProtocol>
//与接收器绑定并设置参数
- (instancetype)initWithReceiver:(Receiver *)receiver paramter:(CGFloat)paramter;
@end
@interface DarkerCommand ()
@property (nonatomic, weak) Receiver *receiver;
@property (nonatomic) CGFloat paramter;
@end
@implementation DarkerCommand
- (instancetype)initWithReceiver:(Receiver *)receiver paramter:(CGFloat)paramter {
self = [super init];
if (self) {
self.receiver = receiver;
self.paramter = paramter;
}
return self;
}
- (void)excute {
[self.receiver makeDarker:self.paramter];
}
- (void)rollBackExcute {
[self.receiver makeLighter:self.paramter];
}
@end
LighterCommond
@interface LighterCommond : NSObject <CommandProtocol>
//与接收器绑定并设置参数
- (instancetype)initWithReceiver:(Receiver *)receiver paramter:(CGFloat)paramter;
@end
@interface LighterCommond ()
@property (nonatomic, weak) Receiver *receiver;
@property (nonatomic) CGFloat paramter;
@end
@implementation LighterCommond
- (instancetype)initWithReceiver:(Receiver *)receiver paramter:(CGFloat)paramter {
self = [super init];
if (self) {
self.receiver = receiver;
self.paramter = paramter;
}
return self;
}
- (void)excute {
[self.receiver makeLighter:self.paramter];
}
- (void)rollBackExcute {
[self.receiver makeDarker:self.paramter];
}
@end
Invoker
@interface Invoker : NSObject
+ (instancetype)shareInstance;
//回退操作
- (void)rollBack;
//添加指令操作
- (void)addAndExcute:(id <CommandProtocol>)command;
@end
@interface Invoker ()
@property (nonatomic, strong) NSMutableArray *queue;
@end
@implementation Invoker
+ (instancetype)shareInstance {
static Invoker *shareInstanceValue = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
shareInstanceValue = [[Invoker alloc] init];
shareInstanceValue.queue = [NSMutableArray array];
});
return shareInstanceValue;
}
- (void)rollBack {
id <CommandProtocol> command = self.queue.lastObject;
[command rollBackExcute];
[self.queue removeLastObject];
}
- (void)addAndExcute:(id <CommandProtocol>)command {
NSParameterAssert(command);
[self.queue addObject:command];
[command excute];
}
@end
Receiver
@interface Receiver : NSObject {
CGFloat _hud;
CGFloat _saturation;
CGFloat _brightness;
CGFloat _alpha;
}
//被服务对象
@property (nonatomic, weak) UIView *clientView;
//变暗
- (void)makeDarker:(CGFloat)pamameter;
//变亮
- (void)makeLighter:(CGFloat)pamameter;
@end
@implementation Receiver
//根据传入的UIView,获取各个维度的值
- (void)setClientView:(UIView *)clientView {
_clientView = clientView;
UIColor *color = _clientView.backgroundColor;
//获取背景色各个维度的值
[color getHue:&_hud
saturation:&_saturation
brightness:&_brightness
alpha:&_alpha];
}
- (void)makeDarker:(CGFloat)pamameter {
_brightness -= pamameter;
_brightness = MAX(0, _brightness);
_clientView.backgroundColor = [UIColor colorWithHue:_hud
saturation:_saturation
brightness:_brightness
alpha:_alpha];
}
- (void)makeLighter:(CGFloat)pamameter {
_brightness += pamameter;
_brightness = MIN(1, _brightness);
_clientView.backgroundColor = [UIColor colorWithHue:_hud
saturation:_saturation
brightness:_brightness
alpha:_alpha];
}
@end
Tag for Button
通过设定tag值,来调用相对应的button
typedef enum : NSUInteger {
kAddButtonTag = 10, // 增加按钮枚举值
kDelButtonTag, // 减少按钮枚举值
kRolButtonTag, // 回退按钮枚举值
} ViewControllerEnumValue;
..........
self.delButton.tag = kDelButtonTag;
self.addButton.tag = kAddButtonTag;
self.rolButton.tag = kRolButtonTag;
..........
if (button.tag == kAddButtonTag) {
} else if (button.tag == kDelButtonTag) {
} else if (button.tag == kRolButtonTag) {
}
协议
协议就是抽象归纳出某一类对象共同拥有的特性