架构设计基础

命令模式

2019-03-13  本文已影响0人  架构师的一小步

命令模式概念

命令模式定义

命令模式-应用场景

场景一:应用程序支持撤销和恢复
场景二:记录请求日志,当系统故障这些命令可以重新被执行
场景三:想用对象参数化一个动作以执行操作,并且用不同命令对象来替换回调函数

命令模式特点

1.没有办法选择撤销(一个个撤销),回退到特定位置需要使用备忘录模式

命令模式角色划分

\color{red}{四个角色}
角色一:接收者:具体业务逻辑(方法)
角色二:命令接口://抽象出操作->具体实现方法定义
角色三:具体命令: 需要持有接收者的引用
角色四:请求者 :持有接受者、具体命令这些类的引用,实现接收者的方法,将方法加入到数组中。

命令模式原理案例

角色一:接收者:具体业务逻辑(方法)
\color{blue}{电脑案例-OC}

//
//  MacComputer.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>

//接收者
@interface MacComputer : NSObject

//开机
-(void)startup;

//关机
-(void)shutdown;

@end

//
//  MacComputer.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "MacComputer.h"

//具体实现
@implementation MacComputer

//开机
-(void)startup{
    //具体实现
    NSLog(@"开机...");
}

//关机
-(void)shutdown{
    //具体实现
    NSLog(@"关机...");
}

@end


角色二:命令接口://抽象出操作->具体实现方法定义

//
//  ComputerCommandProtocol.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#ifndef ComputerCommandProtocol_h
#define ComputerCommandProtocol_h

//角色一:命令接口
//电脑命令接口
@protocol ComputerCommandProtocol<NSObject>

//操作->具体实现方法
-(void)execute;

@end

#endif /* ComputerCommandProtocol_h */

角色三:具体命令: 需要持有接收者的引用

//
//  MacStartupCommand.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "ComputerCommandProtocol.h"
#import "MacComputer.h"

//命令角色特点:持有接收者引用
@interface MacStartupCommand : NSObject<ComputerCommandProtocol>

- (instancetype)init:(MacComputer*)computer;


@end

//
//  MacStartupCommand.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "MacStartupCommand.h"

@interface MacStartupCommand()

//父类引用指向子类实例对象(面向对象编程)->架构设计中以后经常看到->后面讲解的内容都将面向协议
@property(nonatomic, strong) MacComputer* computer;

@end

@implementation MacStartupCommand

- (instancetype)init:(MacComputer*)computer{
    self = [super init];
    if (self) {
        self.computer = computer;
    }
    return self;
}

-(void)execute{
    //具体实现->调用具体逻辑
    [self.computer startup];
}

@end

//
//  MacShutdownCommand.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "ComputerCommandProtocol.h"
#import "MacComputer.h"

@interface MacShutdownCommand : NSObject<ComputerCommandProtocol>

- (instancetype)init:(MacComputer*)computer;

@end
//
//  MacShutdownCommand.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "MacShutdownCommand.h"


@interface MacShutdownCommand()

//父类引用指向子类实例对象(面向对象编程)->架构设计中以后经常看到->后面讲解的内容都将面向协议
@property(nonatomic, strong) MacComputer* computer;

@end

@implementation MacShutdownCommand

- (instancetype)init:(MacComputer*)computer{
    self = [super init];
    if (self) {
        self.computer = computer;
    }
    return self;
}

-(void)execute{
    //具体实现->调用具体逻辑(调用逻辑不同)
    [self.computer shutdown];
}

@end

角色四:请求者 :持有接受者、具体命令这些类的引用,实现接收者的方法,将方法加入到数组中。

//
//  MacInvoker.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "MacStartupCommand.h"
#import "MacShutdownCommand.h"

//请求者
@interface MacInvoker : NSObject

//所有的命令都是客户端决定(内部决定也可以)
- (instancetype)init:(MacStartupCommand*)startup shutdown:(MacShutdownCommand*)shutdown;

-(void)startup;

-(void)shutdown;


@end

//
//  MacInvoker.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/25.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "MacInvoker.h"

@interface MacInvoker()

//父类引用指向子类实例对象(面向对象编程)->架构设计中以后经常看到->后面讲解的内容都将面向协议
@property(nonatomic, strong) id<ComputerCommandProtocol> startupCommand;
@property(nonatomic, strong) id<ComputerCommandProtocol> shutdownCommand;

@end

//请求者(职责)
//请求者特点:执行命令
//持有具体命令对象的引用(指针)
@implementation MacInvoker

- (instancetype)init:(MacStartupCommand*)startup shutdown:(MacShutdownCommand*)shutdown{
    self = [super init];
    if (self) {
        self.startupCommand = startup;
        self.shutdownCommand = shutdown;
    }
    return self;
}

-(void)startup{
    //调用命令
    [self.startupCommand execute];
}

-(void)shutdown{
    [self.shutdownCommand execute];
}

@end

命令模式-案例进阶-动态命令

第一步:分析问题?
很多命令类?->类爆炸(开发中巨大问题)
第二步:解决方案?
动态命令:好处在于我们不需要新建各种命令类(block实现)
命令模式变种(今后当你看到了这些代码结构你要清楚知道这是命令模式变种)->DynamicCommand
回调方式:协议、block、通知
动态命令管理器->DynamicCommandManager
第四步:分析调用流程?
1、添加命令->调用了addCommand方法
2、创建命令->createCommand创建命令
注意:创建了一个block,将block作为了参数传递
3、保存block->赋值给属性
4、调用撤销->undo方法
5、执行命令->执行DynamicCommand对象中的execute方法
6、回调block
7、执行tm方法->toTransform()
架构设计->设计模式->需要你课后复习->反复理解(掌握)
撤销

//
//  DynamicCommand.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TMCommandProtocol.h"
#import "TetrisMachine.h"

typedef void(^DynamicBlock)(TetrisMachine* tm);

//特点一:实现命令协议
//特点二:传递接收者
@interface DynamicCommand : NSObject<TMCommandProtocol>

- (instancetype)init:(TetrisMachine*)tm block:(DynamicBlock)tmBlock;

+(id<TMCommandProtocol>)createCommand:(TetrisMachine*)tm block:(DynamicBlock)tmBlock;

@end

//
//  DynamicCommand.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "DynamicCommand.h"


@interface DynamicCommand()
//父类引用指向子类实例对象(面向对象编程)->架构设计中以后经常看到->后面讲解的内容都将面向协议
@property(nonatomic, strong) TetrisMachine* tm;
@property(nonatomic, strong) DynamicBlock tmBlock;
@end

//解决方案:block实现
@implementation DynamicCommand

- (instancetype)init:(TetrisMachine*)tm block:(DynamicBlock)tmBlock{
    self = [super init];
    if (self) {
        self.tm = tm;
        self.tmBlock = tmBlock;
    }
    return self;
}

-(void)execute{
    self.tmBlock(self.tm);
}

//创建对象的时候由于有的时候初始化参数过于复杂,这个我们可以内部提供
//我的动态命令创建过程,专门有了实现,外部只需要调用即可
//类方法->这是一个小框架->命令模式->万能命令
+(id<TMCommandProtocol>)createCommand:(TetrisMachine*)tm block:(DynamicBlock)tmBlock{
    return [[DynamicCommand alloc] init:tm block:tmBlock];
}

@end

动态命令管理器

//
//  DynamicCommandManager.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TetrisMachine.h"

//动态命令管理器
@interface DynamicCommandManager : NSObject

- (instancetype)init:(TetrisMachine*)tm;

-(void)toLeft;
-(void)toRight;
-(void)toTransform;
-(void)undo;
-(void)undoAll;

@end

//
//  DynamicCommandManager.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "DynamicCommandManager.h"
#import "DynamicCommand.h"

@interface DynamicCommandManager()
//父类引用指向子类实例对象(面向对象编程)->架构设计中以后经常看到->后面讲解的内容都将面向协议
@property(nonatomic, strong) NSMutableArray* commands;
@property(nonatomic, strong) TetrisMachine* tm;
@end

@implementation DynamicCommandManager

- (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{
    //根据方法名称,动态加载执行对象的方法(runtime基础知识)
    //自己复习一下关于runtime基础知识
    //获取到方法对象
    SEL method = NSSelectorFromString(methodName);
    //添加动态命令
    [self.commands addObject:[DynamicCommand createCommand:self.tm block:^(TetrisMachine *tm) {
        //执行回调
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self.tm performSelector:method];
        #pragma clang diagnostic pop
    }]];
}

-(void)undo{
    //倒序(队列->自己设计)
    if (self.commands.count > 0) {
        NSLog(@"撤销如下:...");
        //撤销->DynamicCommand
        [[self.commands lastObject] execute];
        //移除
        [self.commands removeLastObject];
    }
}

-(void)undoAll{
    NSLog(@"撤销所有");
    //倒数删除->课后去实现(循环倒数删除)
    //协议规范写法->语法规范
    for (id<TMCommandProtocol> command in self.commands) {
        [command execute];
    }
    [self.commands removeAllObjects];
}

@end

命令模式-变种-复合命令

//
//  WrapperCommand.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TMCommandProtocol.h"

//命令变种->复合命令:执行多个命令
@interface WrapperCommand : NSObject<TMCommandProtocol>

- (instancetype)init:(NSMutableArray*)commands;

@end

//
//  WrapperCommand.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "WrapperCommand.h"

@interface WrapperCommand()
//父类引用指向子类实例对象(面向对象编程)->架构设计中以后经常看到->后面讲解的内容都将面向协议
@property(nonatomic, strong) NSMutableArray* commands;
@end

@implementation WrapperCommand

- (instancetype)init:(NSMutableArray*)commands{
    self = [super init];
    if (self) {
        self.commands = commands;
    }
    return self;
}

//在我的复合命令中,调用执行多个命令,就叫做复合命令
//复合:多个
-(void)execute{
    for (id<TMCommandProtocol> command in self.commands) {
        [command execute];
    }
}

@end

复合命令管理器

//
//  WrapperCommandManager.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TetrisMachine.h"

//第二步:新建一个复合命令管理器->WrapperCommandManager
@interface WrapperCommandManager : NSObject

- (instancetype)init:(TetrisMachine*)tm;

-(void)toLeft;
-(void)toRight;
-(void)toTransform;
-(void)undo;
-(void)undoAll;

@end

//
//  WrapperCommandManager.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "WrapperCommandManager.h"
#import "DynamicCommand.h"
#import "WrapperCommand.h"

@interface WrapperCommandManager()
@property(nonatomic, strong) NSMutableArray* commands;
@property(nonatomic, strong) TetrisMachine* tm;
@end

@implementation WrapperCommandManager

- (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{
    //根据方法名称,动态加载执行对象的方法(runtime基础知识)
    //自己复习一下关于runtime基础知识
    //获取到方法对象
    SEL method = NSSelectorFromString(methodName);
    //添加动态命令
    [self.commands addObject:[DynamicCommand createCommand: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{
    //倒序(队列->自己设计)
    if (self.commands.count > 0) {
        NSLog(@"撤销如下:...");
        //撤销->DynamicCommand
        [[self.commands lastObject] execute];
        //移除
        [self.commands removeLastObject];
    }
}

-(void)undoAll{
    NSLog(@"撤销所有");
    //倒数删除->课后去实现(循环倒数删除)
    //协议规范写法->语法规范
    //复合命令调用
    WrapperCommand* command = [[WrapperCommand alloc] init:self.commands];
    [command execute];
    [self.commands removeAllObjects];
}

@end

命令模式-案例进阶-泛型命令->优化第三步->系统NSUndoManager实现

重申一次:框架设计->NSUndoManager?->课程就会应用框架
第一步:什么是泛型?
在定义的时候不需要指定类型,在使用的时候指定类型。
第二步:泛型基础知识普及?->档次至少提高2个逼格
OC、Swift、Java、C++…
OC、Swift、Java泛型
C++称之为模版类,模版函数
第三步:学习泛型?
1、新建一个泛型类->泛型命令->GenericsCommand
注意:id是指向泛型类型引用
2、新建一个命令管理类->泛型命令->GenericsCommandManager

//
//  GenericsCommand.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TMCommandProtocol.h"

//万能命令
//案例六:命令模式-案例进阶-泛型命令->优化第三步->系统NSUndoManager实现
//接收者之前写死了
//T:表示任意类型标记(表示符)->Type类型含义->T(ObjectType)
//框架设计中:存在多个泛型(代表有意义)-ObjectType(id)
//泛型扩展性很好
//QQ:510278658
//电话:18670706913(微信)
//语法问题(优化耗时->自己扩展知识)
@interface GenericsCommand<T> : NSObject<TMCommandProtocol>

- (instancetype)init:(T)receiver block:(void(^)(T))commandBlock;

//提供一个创建命令类方法
+(id<TMCommandProtocol>)createCommand:(T)receiver block:(void(^)(T))commandBlock;

@end

//
//  GenericsCommand.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "GenericsCommand.h"


@interface GenericsCommand<T>()
//父类引用指向子类实例对象(面向对象编程)->架构设计中以后经常看到->后面讲解的内容都将面向协议
@property(nonatomic, strong) T receiver;
@property(nonatomic, strong) void(^commandBlock)(T);
@end

@implementation GenericsCommand

- (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>)createCommand:(id)receiver block:(void(^)(id))commandBlock{
    return [[GenericsCommand alloc] init:receiver block:commandBlock];
}

@end

泛型命令管理器

//
//  GenericsCommandManager.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TetrisMachine.h"

@interface GenericsCommandManager : NSObject

- (instancetype)init:(TetrisMachine*)tm;

-(void)toLeft;
-(void)toRight;
-(void)toTransform;
-(void)undo;
-(void)undoAll;

@end

//
//  GenericsCommandManager.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "GenericsCommandManager.h"
#import "GenericsCommand.h"
#import "WrapperCommand.h"

@interface GenericsCommandManager()
@property(nonatomic, strong) NSMutableArray* commands;
@property(nonatomic, strong) TetrisMachine* tm;
@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{
    //根据方法名称,动态加载执行对象的方法(runtime基础知识)
    //自己复习一下关于runtime基础知识
    //获取到方法对象
    SEL method = NSSelectorFromString(methodName);
    //添加动态命令
    [self.commands addObject:[GenericsCommand createCommand:self.tm block:^(TetrisMachine *tm) {
        //执行回调
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self.tm performSelector:method];
#pragma clang diagnostic pop
    }]];
}

-(void)undo{
    //倒序(队列->自己设计)
    if (self.commands.count > 0) {
        NSLog(@"撤销如下:...");
        //撤销->DynamicCommand
        [[self.commands lastObject] execute];
        //移除
        [self.commands removeLastObject];
    }
}

-(void)undoAll{
    NSLog(@"撤销所有");
    //倒数删除->课后去实现(循环倒数删除)
    //协议规范写法->语法规范
    //复合命令调用
    WrapperCommand* command = [[WrapperCommand alloc] init:self.commands];
    [command execute];
    [self.commands removeAllObjects];
}

@end

命令模式-案例进阶-并发处理

1、分析问题?
多线程当中存在同时缓存命令
2、解决方案?
多线程->队列
3、功能实现?
第一步:定义一个并发管理器->QueueCommandMananger

//
//  QueueCommandMananger.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TetrisMachine.h"

@interface QueueCommandMananger : NSObject

- (instancetype)init:(TetrisMachine*)tm;

-(void)toLeft;
-(void)toRight;
-(void)toTransform;
-(void)undo;
-(void)undoAll;

@end

//
//  QueueCommandMananger.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "QueueCommandMananger.h"
#import "GenericsCommand.h"
#import "WrapperCommand.h"

@interface QueueCommandMananger()
@property(nonatomic, strong) NSMutableArray* commands;
@property(nonatomic, strong) TetrisMachine* tm;
@property(nonatomic, strong) dispatch_queue_t queue;
@end

@implementation QueueCommandMananger

- (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, ^{
        //根据方法名称,动态加载执行对象的方法(runtime基础知识)
        //自己复习一下关于runtime基础知识
        //获取到方法对象
        SEL method = NSSelectorFromString(methodName);
        //添加动态命令
        [self.commands addObject:[GenericsCommand createCommand:self.tm block:^(TetrisMachine *tm) {
            //执行回调
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [self.tm performSelector:method];
#pragma clang diagnostic pop
        }]];
    });
}

-(void)undo{
    //倒序(队列->自己设计)
    if (self.commands.count > 0) {
        NSLog(@"撤销如下:...");
        //撤销->DynamicCommand
        [[self.commands lastObject] execute];
        //移除
        [self.commands removeLastObject];
    }
}

-(void)undoAll{
    NSLog(@"撤销所有");
    //倒数删除->课后去实现(循环倒数删除)
    //协议规范写法->语法规范
    //复合命令调用
    WrapperCommand* command = [[WrapperCommand alloc] init:self.commands];
    [command execute];
    [self.commands removeAllObjects];
}

@end


命令模式-案例进阶-block命令(优化)

之前:用的协议
现在:block实现
第一步:定义一个BlockCommandManager命令
为什么有的地方用T,有的地方用id?
规定:
1、声明文件中->指定泛型->T
2、实现文件中->指定具体类型(id万能指针->引用->指向任意对象)

//
//  BlockCommandManager.h
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "TetrisMachine.h"

@interface BlockCommandManager : NSObject

- (instancetype)init:(TetrisMachine*)tm;

-(void)toLeft;
-(void)toRight;
-(void)toTransform;
-(void)undo;
-(void)undoAll;

@end
//
//  BlockCommandManager.m
//  Dream_20180625_CommandPattern_01
//
//  Created by Dream on 2018/6/27.
//  Copyright © 2018年 Tz. All rights reserved.
//

#import "BlockCommandManager.h"
#import "GenericsCommand.h"
#import "WrapperCommand.h"

typedef void(^BlockCommand)(TetrisMachine* tm);

@interface BlockCommandManager()
@property(nonatomic, strong) NSMutableArray* commands;
@property(nonatomic, strong) TetrisMachine* tm;
@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, ^{
        //根据方法名称,动态加载执行对象的方法(runtime基础知识)
        //自己复习一下关于runtime基础知识
        //获取到方法对象
        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{
    //倒序(队列->自己设计)
    if (self.commands.count > 0) {
        NSLog(@"撤销如下:...");
        //撤销->DynamicCommand
        BlockCommand command = [self.commands lastObject];
        command(self.tm);
        //移除
        [self.commands removeLastObject];
    }
}

-(void)undoAll{
    NSLog(@"撤销所有");
    //倒数删除->课后去实现(循环倒数删除)
    //协议规范写法->语法规范
    //复合命令调用
//    WrapperCommand* command = [[WrapperCommand alloc] init:self.commands];
//    [command execute];
    
    for (BlockCommand command in self.commands) {
        command(self.tm);
    }
    [self.commands removeAllObjects];
}

@end


命令模式UML

上一篇下一篇

猜你喜欢

热点阅读