咱們有若干個軍團,軍團有若干功能: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等級對全部的對命令進行排序、記錄等操做...
因而可知,咱們對請求行爲進行了封裝,從而能夠對這個請求對象(命令)進行一系列的操做。並且還化解了調用者和接收者之間的耦合關係。
在如下狀況下可使用命令模式:
命令模式的優勢
命令模式的缺點