將“請(qǐng)求”封裝成對(duì)象,以便使用不同的請(qǐng)求、隊(duì)列、或者日志來(lái)參數(shù)化其他對(duì)象。命令模式也支持可撤銷的操作。
每一位召喚師都有QWER4個(gè)技能,當(dāng)我們按下鍵盤上(或其他外設(shè))的Q按鈕后,我們操控的召喚師就會(huì)釋放Q技能進(jìn)行攻擊。整個(gè)過(guò)程可以使用命令模式來(lái)描述。命令模式可以將請(qǐng)求者與接收者之間解耦。
命令模式是在特定接收者上綁定一組動(dòng)作來(lái)封裝成一個(gè)請(qǐng)求(命令對(duì)象),而這個(gè)請(qǐng)求只暴露出一個(gè)execute方法,當(dāng)此方法被調(diào)用的時(shí)候,接收者就會(huì)負(fù)責(zé)進(jìn)行這些動(dòng)作。而對(duì)于外面來(lái)看,其他對(duì)象不知道究竟是哪個(gè)接收者進(jìn)行了哪些動(dòng)作,只知道如果調(diào)用了execute方法,請(qǐng)求的目的就能達(dá)到。
命令模式還能實(shí)現(xiàn)撤銷操作,也比較簡(jiǎn)單,只需讓接收者實(shí)現(xiàn)命令的相反操作即可。
1. 簡(jiǎn)單的命令模式

@protocol Command <NSObject>
- (void)execute; // 執(zhí)行命令
- (void)undo; // 撤銷命令
@end
@implementation Skill_Q {
Summoner *_summoner;
}
- (instancetype)initWithSummoner:(Summoner *)summoner {
self = [super init];
if (self) {
_summoner = summoner;
}
return self;
}
- (void)execute {
[_summoner touchSkillWithNumber:@"Q"];
}
- (void)undo {
[_summoner cancelSkillWithNumber:@"Q"];
}
@end

@interface OuterDevice : NSObject
@property (nonatomic, strong, readonly) NSMutableDictionary *commandMap;
- (void)buttonAddCommand:(id<Command>)command number:(NSString *)number;//給外設(shè)按鈕增加命令
- (void)pressedButtonWithNumber:(NSString *)number;//按下按鈕
- (void)undoPressedButtonWithNumber:(NSString *)number;//撤銷按下按鈕操作
@end
@implementation OuterDevice
- (instancetype)init {
self = [super init];
if (self) {
_commandMap = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)buttonAddCommand:(id<Command>)command number:(NSString *)number {
[_commandMap setObject:command forKey:number];
}
- (void)pressedButtonWithNumber:(NSString *)number {
id<Command> command = [_commandMap objectForKey:number];
[command execute];
}
- (void)undoPressedButtonWithNumber:(NSString *)number {
id<Command> command = [_commandMap objectForKey:number];
[command undo];
}
@end
可能你覺得接收者不一定要存在,可以讓命令對(duì)象直接實(shí)現(xiàn)execute方法。但是,這樣的做法使得調(diào)用者與接收者之間的耦合程度增加,而且還不能將接收者當(dāng)作參數(shù)傳遞給命令。所以,還是將命令對(duì)象設(shè)計(jì)的簡(jiǎn)單、傻瓜點(diǎn)更合適。
具體代碼傳送門
2. 隊(duì)列請(qǐng)求
命令模式可以將一個(gè)接收者和一組動(dòng)作打包,供不同的線程調(diào)用,我們可以利用這個(gè)特性來(lái)創(chuàng)建隊(duì)列請(qǐng)求操作。比如在隊(duì)列的一端添加各式各樣的命令對(duì)象,而線程從隊(duì)列的另一端中取出命令對(duì)象,調(diào)用其execute方法便能完成相關(guān)任務(wù)。線程不必知道具體的命令是什么,這樣就達(dá)到了解耦。
3. 日志
我們還可以利用命令模式將用戶的動(dòng)作記錄到日志中,通過(guò)序列化把命令對(duì)象存儲(chǔ)到磁盤中,一旦系統(tǒng)死機(jī),重啟后我們就可以將命令對(duì)象重新加載并執(zhí)行,這樣就使系統(tǒng)恢復(fù)到了上一次死機(jī)前的那一刻。
傾情告白:為交互對(duì)象之間的松耦合設(shè)計(jì)而努力!
關(guān)注微信公眾號(hào)CodingArtist,可以第一時(shí)間得到文章更新通知! _