咱们有若干个军团,军团有若干功能:1.陆地攻击目标 2.轰炸目标 3.保护目标 4.从目标撤退等。
将军能够下达指令给军团,调用军团的功能。编程
在一场battle中,将军指挥若定,给旗下的军团下达了一系列的命令:
攻击1号山地
攻击4号山地
保护3号山地
......atom
若是用类去实现,能够这样spa
将军直接调用军团A的attack:方法,一样也能够直接调用bomb、protect方法,这样并无问题。设计
若是咱们引入新的需求:
3d
咱们须要对将军下发的命令进行排队(下发多条命令时须要按照优先级执行)、记录执行命令、撤销命令、传递命令、重复执行等相关操做。日志
若是仍是按照上面直接调用来作,基本上很难实现,有如下几个主要问题:code
不一样军种攻击方法不一样,须要知道每一个类或方法的细节才能调用。致使彼此拥有高耦合度。对象
对命令进行操做(撤销、记录等)将很是复杂blog
命令不可传递和复用排序
须要把命令封装起来,这样咱们就能够对这个封装的对象进行种种操做了
好比将军下的命令是一封信,信里上标明执行的等级,攻击的目标等参数信息。 当若干封信来的时候咱们能够根据等级排列,执行完后还能够把信交给其它军团再次执行。。。
调用者和执行者解耦
将军(调用者)封装一个命令对象,哪一个军团接到这个命令对象就执行这个命令,调用者不用关心执行的细节,只需关注命令自己便可。
以下图:
命令模式: 将请求封装为一个对象,从而可用不一样的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操做。
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。
在软件设计中,咱们常常须要向某些对象发送请求,可是并不知道请求的接收者是谁,也不知道被请求的操做是哪一个,咱们只需在程序运行时指定具体的请求接收者便可,此时,可使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。
命令模式能够对发送者和接收者彻底解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只须要知道如何发送请求,而没必要知道如何完成请求。这就是命令模式的模式动机。
Command模式是最让我疑惑的一个模式。它实际上不是个很具体,规定不少的模式,正是这个灵活性,让人容易产生confuse。
根据上面的场景来进行code实现;
接受者是命令模式中去执行具体操做的对象,这里指的具体军团
@interface Legion : NSObject @property (nonatomic, copy) NSString *name; - (instancetype)initWithName: (NSString *)name; // 攻击 - (void)attack:(NSString *)target; // 轰炸 - (void)bomb:(NSString *)target; // 保护 - (void)protect:(NSString *)target; // 撤回 - (void)recall:(NSString *)target; @end @implementation Legion - (instancetype)initWithName: (NSString *)name { self = [super init]; if (self) { _name = name; } return self; } - (void)attack:(NSString *)target { NSLog(@"军团: %@--------攻击: %@", self.name, target); } - (void)bomb:(NSString *)target { NSLog(@"军团: %@--------轰炸: %@", self.name, target); } - (void)protect:(NSString *)target { NSLog(@"军团: %@--------保护: %@", self.name, target); } - (void)recall:(NSString *)target { NSLog(@"军团: %@--------撤回: %@", self.name, target); } @end
命令对象中暴露了指定的调用execute方法,命令的调用者和接收者针对抽象的命令类编写,从而达到解耦合的目的。
发起命令的对象彻底不知道具体实现对象是谁,也不知道如何实现。
#import "Legion.h" @interface Command : NSObject @property (nonatomic, assign) NSInteger level; @property (nonatomic, strong) Legion *legion; @property (nonatomic, copy) NSString *target; - (instancetype)initWithReciver:(Legion *)legion target:(NSString *)target; - (void)attack; - (void)recall; @end @implementation Command - (instancetype)initWithReciver:(Legion *)legion target:(NSString *)target { self = [super init]; if (self) { _legion = legion; _target = target; } return self; } - (void)attack { } - (void)recall { } @end
#import "Command.h" @interface LandAttackCommand : Command - (void)attack; - (void)recall; @end @implementation LandAttackCommand - (void)attack { [self.legion attack:self.target]; } - (void)recall { [self.legion recall:self.target]; } @end
#import "Command.h" @interface AirAttackCommand : Command - (void)attack; - (void)recall; @end @implementation AirAttackCommand - (void)attack { [self.legion bomb:self.target]; } - (void)recall { [self.legion recall:self.target]; } @end
这里咱们能够写一个调用者类,用这个类负责命令的建立和调用,还有对命令的管理(好比排序、日志记录等等)。
这里我就不单独写了,具体业务中能够依据具体状况去编写。
下面的调用例子把客户端和调用者放在一块儿不作具体区分。
Legion *legionA = [[Legion alloc] initWithName:@"军团A"]; Command *landComand1 = [[LandAttackCommand alloc] initWithReciver:legionA target:@"4号高地"]; landComand1.level = 100; Command *landComand2 = [[LandAttackCommand alloc] initWithReciver:legionA target:@"5号高地"]; landComand2.level = 200; Command *airAttackCommand1 = [[AirAttackCommand alloc] initWithReciver:legionA target:@"4号高地"]; airAttackCommand1.level = 50; Command *airAttackCommand2 = [[AirAttackCommand alloc] initWithReciver:legionA target:@"5号高地"]; airAttackCommand2.level = 500; NSArray *commandList = @[landComand1, landComand2, airAttackCommand1, airAttackCommand2]; for (Command *comand in commandList) { [comand attack]; } // 命令传递 Legion *legionB = [[Legion alloc] initWithName:@"军团B"]; landComand1.legion = legionB; [landComand1 attack]; // 撤销 [landComand1 recall]; // 能够根据level等级对全部的对命令进行排序、记录等操做...
因而可知,咱们对请求行为进行了封装,从而能够对这个请求对象(命令)进行一系列的操做。并且还化解了调用者和接收者之间的耦合关系。
在如下状况下可使用命令模式:
命令模式的优势
命令模式的缺点