第一點:將一個請求封裝成爲一個對象,從而讓用戶使用不一樣的請求將客戶端參數化。 第二點:對請求排隊或者紀錄請求日誌,以及支持撤銷操做。 讓咱們程序擴展性更加好了,耦合下降了。swift
命令模式-應用場景: 當須要將方法調用包裝成一個對象,以延時方法調用,或者讓其餘組件在對其內部實現細節不瞭解的狀況下進行調用的時候能夠使用命令模式api
場景一:應用程序支持撤銷和恢復 場景二:記錄請求日誌,當系統故障這些命令能夠從新被執行 場景三:想用對象參數化一個動做以執行操做,而且用不一樣命令對象來替換回調函數閉包
以命令模式進行分析:(思路) 管理器(請求者)--(調用)-->具體命令--(接口)-->接受者執行 命令模式至少有的4個角色:併發
案例需求:記錄全部操做,支持回退(撤銷)。app
import Foundation //命令接口 protocol CommandProtocol { func excute() } //具體命令 class TMLeftCommand: CommandProtocol { private var tm : TetrisMachine init(_ tm:TetrisMachine) { self.tm = tm } func excute() { self.tm.Toleft() } } class TMRightCommand: CommandProtocol { private var tm : TetrisMachine init(_ tm:TetrisMachine) { self.tm = tm } func excute() { self.tm.ToRight() } } class TMTransformCommand: CommandProtocol { private var tm : TetrisMachine init(_ tm:TetrisMachine) { self.tm = tm } func excute() { self.tm.ToTransform() } } //接受者 class TetrisMachine : NSObject { func Toleft(){ print("left") } func ToRight(){ print("right") } func ToTransform(){ print("transform") } } //請求者 class TetrisMachineManger{ private var commands = Array<CommandProtocol>() private var tm : TetrisMachine private var left : TMLeftCommand private var right : TMRightCommand private var transform : TMTransformCommand init(tm:TetrisMachine, left:TMLeftCommand,right:TMRightCommand,transform:TMTransformCommand) { self.left = left self.right = right self.transform = transform self.tm = tm } func Toleft(){ self.left.excute() self.commands.append(TMLeftCommand(self.tm)) } func ToRight(){ self.right.excute() self.commands.append(TMRightCommand(self.tm)) } func ToTransform(){ self.transform.excute() self.commands.append(TMTransformCommand(self.tm)) } func undo(){ if self.commands.count > 0{ self.commands.removeLast().excute() } } } //最後調用 let tm = TetrisMachine() let left = TMLeftCommand(tm) let right = TMRightCommand(tm) let transform = TMTransformCommand(tm) let manager = TetrisMachineManger(tm: tm, left: left, right: right, transform: transform) manager.Toleft() manager.ToRight() manager.ToTransform() manager.undo() //打印 left right transform transform
什麼是泛型:在定義的時候不須要指定類型,在使用的時候指定類型。(ObjectType)框架
1.聲明文件->指定泛型->T(任意標識) 2.實現文件->指定具體類型(id萬能指針->引用->指向任意對象)dom
[@interface](https://my.oschina.net/u/996807) NSMutableArray<ObjectType> : NSArray<ObjectType>
#import <Foundation/Foundation.h> #import "TMCommandProtocol.h" //T:表示任意類型標記(表示符) [@interface](https://my.oschina.net/u/996807) GenericsCommand<T> : NSObject<TMCommandProtocol> -(instancetype)init:(T)receiver block:(void(^)(T)) commandBlock; +(id<TMCommandProtocol>)creatCommand:(T)receiver block:(void(^)(T)) commandBlock; [@end](https://my.oschina.net/u/567204) #import "GenericsCommand.h" [@interface](https://my.oschina.net/u/996807) GenericsCommand<T>() [@property](https://my.oschina.net/property) (nonatomic,strong)T receiver; @property (nonatomic,strong)void(^commandblock)(T); @end @implementation GenericsCommand //id 是指向泛型的引用 -(instancetype)init:(id)receiver block:(void(^)(id))commandBlock{ self = [super init]; if (self){ self.receiver = receiver ; self.commandblock = commandBlock; } return self; } -(void)execute{ self.commandblock(self.receiver); } +(id<TMCommandProtocol>)creatCommand:(id)receiver block:(void(^)(id)) commandBlock{ return [[GenericsCommand alloc]init:receiver block:commandBlock]; } @end #import <Foundation/Foundation.h> #import "TetrisMachine.h" @interface GenericsCommandManager : NSObject -(instancetype)init:(TetrisMachine *)tm; -(void)Toleft; -(void)Toright; -(void)Totransform; -(void)undo; -(void)Allundo; @end #import "GenericsCommandManager.h" #import "GenericsCommand.h" @interface GenericsCommandManager() @property (nonatomic,strong)TetrisMachine *tm; @property (nonatomic,strong)NSMutableArray *commands; @end @implementation GenericsCommandManager -(instancetype)init:(TetrisMachine *)tm{ self = [super init]; if (self){ self.tm = tm ; self.commands = [[NSMutableArray alloc]init]; } return self; } -(void)Toleft{ [self addCommand:@"Toleft"]; [self.tm Toleft];//執行命令 } -(void)Toright{ [self addCommand:@"ToRight"]; [self.tm ToRight]; } -(void)Totransform{ [self addCommand:@"ToTransform"]; [self.tm ToTransform]; } //管理器動態添加命令 -(void)addCommand:(NSString *)methodName{ //根據方法名稱,動態加載執行對象的方法 SEL method = NSSelectorFromString(methodName); //添加動態命令 [self.commands addObject:[GenericsCommand creatCommand:self.tm block:^(TetrisMachine *tm) { //執行回調 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [tm performSelector:method]; #pragma clang diagnostic pop }]]; } -(void)undo{ NSLog(@"撤銷"); if (self.commands.count > 0){ //撤銷 [[self.commands lastObject]execute]; //移除 [self.commands removeLastObject]; } } -(void)Allundo{ NSLog(@"刪除全部"); //倒序co NSArray* reversedArray = [[self.commands reverseObjectEnumerator] allObjects]; for (id<TMCommandProtocol> command in reversedArray){ [command execute]; } [self.commands removeAllObjects]; } @end
#import <Foundation/Foundation.h> #import "TetrisMachine.h" @interface BlockCommandManager : NSObject -(instancetype)init:(TetrisMachine *)tm; -(void)Toleft; -(void)Toright; -(void)Totransform; -(void)undo; -(void)Allundo; @end #import "BlockCommandManager.h" typedef void (^BlockCommand)(TetrisMachine *tm); @interface BlockCommandManager() @property (nonatomic,strong)TetrisMachine *tm; @property (nonatomic,strong)NSMutableArray *commands; @property (nonatomic,strong)dispatch_queue_t queue; @end @implementation BlockCommandManager -(instancetype)init:(TetrisMachine *)tm{ self = [super init]; if (self){ self.tm = tm ; self.commands = [[NSMutableArray alloc]init]; self.queue = dispatch_queue_create("Command", NULL); } return self; } -(void)Toleft{ [self addCommand:@"Toleft"]; [self.tm Toleft];//執行命令 } -(void)Toright{ [self addCommand:@"ToRight"]; [self.tm ToRight]; } -(void)Totransform{ [self addCommand:@"ToTransform"]; [self.tm ToTransform]; } //管理器動態添加命令 -(void)addCommand:(NSString *)methodName{ //併發 dispatch_sync(self.queue, ^{ //根據方法名稱,動態加載執行對象的方法 SEL method = NSSelectorFromString(methodName); //添加動態命令 保存的是block [self.commands addObject:^(TetrisMachine *tm){ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [tm performSelector:method]; #pragma clang diagnostic pop }]; }); } -(void)undo{ NSLog(@"撤銷"); if (self.commands.count > 0){ //撤銷 BlockCommand command =[self.commands lastObject]; command(self.tm); //移除 [self.commands removeLastObject]; } } -(void)Allundo{ NSLog(@"刪除全部"); //倒序co NSArray* reversedArray = [[self.commands reverseObjectEnumerator] allObjects]; for (BlockCommand command in reversedArray){ command(self.tm); } [self.commands removeAllObjects]; } @end
import UIKit class GenericsCommand<T>: CommandProtocol { private var tm : T private var block : (T)->Void init(receiver : T ,block:@escaping (T) -> Void) { self.tm = receiver; self.block = block } func excute() { self.block(self.tm) } class func creatCommand(receiver:T,block:@escaping (T)->Void)->CommandProtocol { return GenericsCommand (receiver: receiver, block: block) } } import UIKit class GenericsCommandInvoke: NSObject { private var reveiver : TetrisMachine private var commands = Array<CommandProtocol>() init(reveiver:TetrisMachine) { self.reveiver = reveiver } func toLeft(){ self.addCommand(method: TetrisMachine.Toleft) self.reveiver.Toleft() } func toRight(){ self.addCommand(method: TetrisMachine.ToRight) self.reveiver.ToRight() } func toTransform(){ self.addCommand(method: TetrisMachine.ToTransform) self.reveiver.ToTransform() } //使用的指定 private func addCommand(method:@escaping(TetrisMachine)->()->(Void)){ self.commands.append(GenericsCommand<TetrisMachine>(receiver: self.reveiver, block: { (tm) in method(tm)() })) } //modify 多個直接撤銷 func undo(){ if self.commands.count>0{ self.commands.removeLast().excute() } } func undoAll(){ // for commands in self.commands{ // commands.excute() // } WrapperCommand(commands: self.commands).excute(); self.commands.removeAll() } }
import UIKit class BlockCommandInvoke: NSObject { private var queue = DispatchQueue(label: "Command") private var reveiver : TetrisMachine typealias BlockCommand = ((TetrisMachine) ->Void) private var commands = Array<BlockCommand>() init(reveiver:TetrisMachine) { self.reveiver = reveiver } func toLeft(){ self.addCommand(method: TetrisMachine.Toleft) self.reveiver.Toleft() } func toRight(){ self.addCommand(method: TetrisMachine.ToRight) self.reveiver.ToRight() } func toTransform(){ self.addCommand(method: TetrisMachine.ToTransform) self.reveiver.ToTransform() } // private func addCommand(method:@escaping(TetrisMachine)->()->(Void)){ self.queue.sync { self.commands.append({tm in method(tm)() }) } } //modify 多個直接撤銷 func undo(){ if self.commands.count > 0{ self.commands.removeLast()(self.reveiver) } } func undoAll(){ for command in self.commands{ command(self.reveiver) } self.commands.removeAll() } }
參考文章:https://www.jianshu.com/p/c62e1bc04bf1 NSUndoManager:https://nshipster.cn/nsundomanager/函數