第一点:将一个请求封装成为一个对象,从而让用户使用不同的请求将客户端参数化。 第二点:对请求排队或者纪录请求日志,以及支持撤销操作。 让我们程序扩展性更加好了,耦合降低了。
命令模式-应用场景: 当需要将方法调用包装成一个对象,以延时方法调用,或者让其他组件在对其内部实现细节不了解的情况下进行调用的时候可以使用命令模式
场景一:应用程序支持撤销和恢复 场景二:记录请求日志,当系统故障这些命令可以重新被执行 场景三:想用对象参数化一个动作以执行操作,并且用不同命令对象来替换回调函数
以命令模式进行分析:(思路) 管理器(请求者)--(调用)-->具体命令--(接口)-->接受者执行 命令模式至少有的4个角色:
- 命令接口(抽象)(CommandProtocol):TMCommandProtocol
- 具体命令(ConcrateCommand) 比如:1.向左-> TMLeftCommand 2.向右-> TMRightCommand 3.变型-> TMTransformCommand
- 接受者(Reciever):TetrisMachine
- 请求者 (命令管理器)(Invoker):TetrisMachineManger管理回调命令
案例需求:记录所有操作,支持回退(撤销)。
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() 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() //打印leftrighttransformtransform
5.1 命令模式 泛型设计 动态调用
什么是泛型:在定义的时候不需要指定类型,在使用的时候指定类型。(ObjectType)
1.声明文件->指定泛型->T(任意标识) 2.实现文件->指定具体类型(id万能指针->引用->指向任意对象)
[@interface](https://my.oschina.net/u/996807) NSMutableArray: NSArray
#import#import "TMCommandProtocol.h"//T:表示任意类型标记(表示符)[@interface](https://my.oschina.net/u/996807) GenericsCommand : NSObject -(instancetype)init:(T)receiver block:(void(^)(T)) commandBlock;+(id )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 ()[@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 )creatCommand:(id)receiver block:(void(^)(id)) commandBlock{ return [[GenericsCommand alloc]init:receiver block:commandBlock];}@end#import #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 command in reversedArray){ [command execute]; } [self.commands removeAllObjects];}@end
5.2 命令模式 案例进阶 block闭包 && 并发(优化框架)
#import#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
5.3swift优化泛型命令
import UIKitclass GenericsCommand: 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 UIKitclass GenericsCommandInvoke: NSObject { private var reveiver : TetrisMachine private var commands = Array () 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 (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() }}
5.4swift优化闭包命令
import UIKitclass BlockCommandInvoke: NSObject { private var queue = DispatchQueue(label: "Command") private var reveiver : TetrisMachine typealias BlockCommand = ((TetrisMachine) ->Void) private var commands = Array() 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() }}
参考文章: NSUndoManager: