示例1:
到飯館吃飯,你做爲顧客,一般的狀況是:服務員把菜單拿給你,點菜完成後,服務員就拿着菜單去向後廚交代。你只須要坐等菜好就能夠了。你不須要知道誰給你作菜,也不須要知道他們怎麼去作。只須要點菜就能夠了。html
示例2:
日常咱們開電腦的時候,只須要按下開機按鈕就不用管了,電腦就開始啓動、屏幕亮了起來。不須要關心電腦裏主板、顯卡、硬盤、操做系統等一些列的加載與檢測等。git
上述例子中點菜的顧客和開機的用戶都是隻作了下發命令的一個動做,其它都不須要管,就會有具體的行爲或功能產生。將上述流程用編程的概念描述出來:客戶端只是想要發出命令或者請求,不關心請求的真正接收者是誰,也不關心具體如何實現,並且同一個請求動做能夠有不一樣的請求內容,固然具體的處理功能也不同。這就是命令模式要解決的問題。github
命令模式(Command Pattern) 將一個請求封裝爲一個對象,從而使咱們能夠使用不一樣的請求對客戶進行參數化;對請求排隊或者記錄請求日誌,以及支持可撤銷的操做。命令模式是一種對象行爲型模式,還被稱爲動做(Action)
模式或事物(Transaction)
模式。編程
命令模式的UML圖以下: 設計模式
Command
接口,這裏只是去調用真正的Receiver
來實現真正要執行的功能或行爲。下邊以電腦開機和重啓兩個命令來實現命令模式,UML圖以下: bash
//***********************命令接口***********************
@protocol ComputerCommand <NSObject>
@property (nonatomic,copy)NSString *name;
- (void)execute;
@end
//***********************具體命令***************
@interface OpenCommand : NSObject<ComputerCommand>//開機命令
- (instancetype)initWithReceiver:(MainBoard *)mainBoard cmdName:(NSString *)cmdName;
@end
interface OpenCommand ()
@property (nonatomic,strong)MainBoard *mainBoard;
@end
@implementation OpenCommand
@synthesize name = _name;
- (instancetype)initWithReceiver:(MainBoard *)mainBoard cmdName:(NSString *)cmdName
{
if (self = [super init]) {
_mainBoard = mainBoard;
_name = cmdName;
}
return self;
}
- (void)execute
{
[self.mainBoard openComputer];
}
@end
//重啓命令與開機命令代碼相似,就再也不往上貼了
//***********************命令接收者(真正的命令實現者)*********
@interface MainBoard : NSObject
- (void)openComputer;
- (void)closeComputer;
- (void)resetComputer;
@end
@implementation MainBoard
- (void)openComputer
{
NSLog(@"接通電源、檢查設備、裝載系統、運行開機");
}
- (void)closeComputer
{
NSLog(@"關機");
}
- (void)resetComputer
{
NSLog(@"正在重啓,請稍後,重啓成功");
}
@end
//***********************命令觸發者***********************
@interface ComputerBox : NSObject//Invoker 命令在主箱上
- (void)configOpenCommand:(id<ComputerCommand>)command;
- (void)configResetCommand:(id<ComputerCommand>)command;
- (void)pressOpenButton;
- (void)pressResetButton;
@end
@interface ComputerBox ()
@property (nonatomic,strong)id<ComputerCommand> openCommand;
@property (nonatomic,strong)id<ComputerCommand> resetCmd;
@end
@implementation ComputerBox
- (void)configOpenCommand:(id<ComputerCommand>)command
{
_openCommand = command;
}
- (void)configResetCommand:(id<ComputerCommand>)command
{
_resetCmd = command;
}
- (void)pressOpenButton
{
[self.openCommand execute];
}
- (void)pressResetButton
{
[self.resetCmd execute];
}
@end
//***********************將命令和接收者組裝起來***************
@interface ComputerClient : NSObject
+ (id<ComputerCommand>)configedCommandWithCmdName:(NSString *)cmdName;
@end
@implementation ComputerClient
+ (id<ComputerCommand>)configedCommandWithCmdName:(NSString *)cmdName
{
MainBoard *mainBoard = [MainBoard new];
if ([cmdName isEqualToString:@"open"]) {
OpenCommand *openCmd = [[OpenCommand alloc]initWithReceiver:mainBoard cmdName:cmdName];
return openCmd;
}else if ([cmdName isEqualToString:@"reset"]){
ResetCommand *resetCmd = [[ResetCommand alloc]initWithReceiver:mainBoard cmdName:cmdName];
return resetCmd;
}
return nil;
}
@end
//***********************外部調用***********************
//將命令和接收者組裝
id<ComputerCommand> openCmd = [ComputerClient configedCommandWithCmdName:@"open"];
id<ComputerCommand> resetCmd = [ComputerClient configedCommandWithCmdName:@"reset"];
//Invoker
ComputerBox *box = [[ComputerBox alloc]init];
//開機
[box configOpenCommand:openCmd];//將命令給到觸發者。能夠將命令與接收者的組裝也讓Invoker實現。
[box pressOpenButton];//點擊開機按鈕。觸發命令
//重啓
[box configResetCommand:resetCmd];
[box pressResetButton];
複製代碼
實現中的ComputerBox
做爲Invoker(觸發者)
角色,持有了開機命令和重啓命令。ComputerClient
類的做用就是將不一樣的命令和對應 的真正實現者Receiver
裝配起來,創建關係,該類的做用也能夠由Invoker實現,不一樣的狀況能夠根據具體的需求本身來靈活變更實現。ui
命令模式還能夠實現許多其餘功能,例如:撤銷操做、宏命令(一系列命令的組合)、隊列請求等。在這裏筆者只是簡單的介紹了命令模式,對於命令模式的其它功能實現,後續會慢慢補充。atom
以上做爲筆者本身的理解與記錄,水平有限,若有理解錯誤的地方,還請指出。謝謝!spa
Demo地址操作系統
參考致謝:
《研磨設計模式》