命令模式

作者: 架构师的一小步 | 来源:发表于2019-03-13 10:21 被阅读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
      特点:实现协议->TMCommandProtocol
      框架设计有点枯燥->一旦你笑话了,你功力绝对大增
      第二步:新建一个复合命令管理器->WrapperCommandManager
      第三步:总结
      以后你看到了这样的代码结构,框架结构,你要清楚知道这是复合命令(变种)
    //
    //  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

    相关文章

      网友评论

        本文标题:命令模式

        本文链接:https://www.haomeiwen.com/subject/yhfzpqtx.html