设计模式-命令模式

栏目: IOS · 发布时间: 4年前

内容简介:上述例子中点菜的顾客和开机的用户都是只做了下发命令的一个动作,其它都不需要管,就会有具体的行为或功能产生。将上述流程用编程的概念描述出来:客户端只是想要发出命令或者请求,不关心请求的真正接收者是谁,也不关心具体如何实现,而且同一个请求动作可以有不同的请求内容,当然具体的处理功能也不一样。这就是

示例1: 到饭馆吃饭,你作为顾客,通常的情况是:服务员把菜单拿给你,点菜完成后,服务员就拿着菜单去向后厨交代。你只需要坐等菜好就可以了。你不需要知道谁给你做菜,也不需要知道他们怎么去做。只需要点菜就可以了。

示例2: 平常我们开电脑的时候,只需要按下开机按钮就不用管了,电脑就开始启动、屏幕亮了起来。不需要关心电脑里主板、显卡、硬盘、操作系统等一些列的加载与检测等。

上述例子中点菜的顾客和开机的用户都是只做了下发命令的一个动作,其它都不需要管,就会有具体的行为或功能产生。将上述流程用编程的概念描述出来:客户端只是想要发出命令或者请求,不关心请求的真正接收者是谁,也不关心具体如何实现,而且同一个请求动作可以有不同的请求内容,当然具体的处理功能也不一样。这就是 命令模式 要解决的问题。

模式定义

命令模式(Command Pattern)将一个请求封装为一个对象,从而使我们可以使用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,还被称为 动作(Action) 模式或 事物(Transaction) 模式。

命令模式的UML图如下:

设计模式-命令模式
  • Command :定义命令的接口(协议),声明执行的方法。
  • ConcreteCommand :具体的命令,实现 Command 接口,这里只是去调用真正的 Receiver 来实现真正要执行的功能或行为。
  • Receiver :命令接收者,命令行为的真正实现者。任何类都可能成为一个接收者,只要能够实现命令要求的功能。
  • Invoker :触发者,触发命令执行。通常会持有命令。
  • Client :创建具体的命令,并且把命令对象与接收者对象组装好。【这里并不是平常所说的客户端调用,客户端调用是从Invoker开始的】

具体实现

下边以电脑开机和重启两个命令来实现命令模式,UML图如下:

设计模式-命令模式
//***********************命令接口***********************
@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实现,不同的情况可以根据具体的需求自己来灵活变动实现。

总结

  • 命令模式的本质是 封装请求 :命令模式的关键是把请求封装称为命令对象,然后就可以对这个对象进行一系列处理。
  • 命令模式的优点:命令模式使得发起命令的对象--->客户端,和具体实现命令的对象--->接受者对象完全解耦。即发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。

命令模式还可以实现许多其他功能,例如:撤销操作、宏命令(一系列命令的组合)、队列请求等。在这里笔者只是简单的介绍了命令模式,对于命令模式的其它功能实现,后续会慢慢补充。

以上作为笔者自己的理解与记录,水平有限,如有理解错误的地方,还请指出。谢谢!

Demo地址

参考致谢:

《研磨设计模式》

《图说设计模式》


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法竞赛入门经典(第2版)

算法竞赛入门经典(第2版)

刘汝佳 / 清华大学出版社 / 2014-6-1 / CNY 49.80

《算法竞赛入门经典(第2版)》是一本算法竞赛的入门与提高教材,把C/C++语言、算法和解题有机地结合在一起,淡化理论,注重学习方法和实践技巧。全书内容分为12 章,包括程序设计入门、循环结构程序设计、数组和字符串、函数和递归、C++与STL入门、数据结构基础、暴力求解法、高效算法设计、动态规划初步、数学概念与方法、图论模型与算法、高级专题等内容,覆盖了算法竞赛入门和提高所需的主要知识点,并含有大量......一起来看看 《算法竞赛入门经典(第2版)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具