命令模式:

命令模式

这个设计模式将对象封装成了一个请求获取操作,这个封装请求比一个原始的请求更加的灵活,且可以在对象之间传递,稍后存储,动态修改获取放到一个队
列之中。苹果公司是用Target-action机制和Invocation实现的,你可以在苹果的官方文档中去知道更多的关于Target-
Action,但是Invocation使用包含一个Target对象的NSInvocation类,一个方法选择器和一些参数。这个对象可以根据需要动
态的改变和执行,在命令模式中这是一个完美的例子,它解除耦合了发送对象和接收对象,且可以持续的坚持一个或者一系列请求。

如何使用命令模式:

早莫深入动作的invocation之前,你需要去设置撤销(undo action)动作的框架,所以你必须定义一个UIToolBar 和undo stack(撤销栈)上所需要的可变数组。

在ViewController.m的扩展中键入这些代码:

UIToolbar *toolBar;  
   
tableArray *undoStack;

    这创建了一个为了这些操作而添加显示的toolbar,还要一个数组去去作为命令队列。

    添加下面的代码到ViewDidLoad的结尾:

    toolBar = [[UIToolbaralloc]init];  
       
        UIBarButtonItem *undoBtm= [[UIBarButtonItemalloc]initWithBarButtonSystemItem:UIBarButtonSystemItemUndotarget:selfaction:@selector(undoAction)];  
       
        undoBtm.enabled = NO;  
       
        UIBarButtonItem *space =[[UIBarButtonItemalloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpacetarget:nilaction:nil];  
       
        UIBarButtonItem *delete =[[UIBarButtonItemalloc]initWithBarButtonSystemItem:UIBarButtonSystemItemTrash  
       
                                                                              target:selfaction:@selector(deleteAction)];  
       
        [toolBarsetItems:@[undoBtm,space,delete]];  
       
        [self.viewaddSubview:toolBar];  
       
    undoStack = [[NSMutableArrayalloc]init];

    上面的代码创建了一个toolbar,它有两个按钮和一个可变的空格。这个撤销按钮被禁止了因为这个undo stack一开始是空的。

    同样,因为这个toolbar没有根据frame来初始化,所以这个在viewDidload中frame的大小还没有设置。所以通过下面的一些代码在一旦视图的frame被最终设置好了以后设置这个frame。

    -(void)viewWillLayoutSubviews  
       
    {  
       
        toolBar.frame = CGRectMake(0, self.view.frame.size.height-44, self.view.frame.size.width,44);  
       
        dataTable.frame = CGRectMake(0, 130, self.view.frame.size.width, self.view.frame.size.height-200) ;  
       
    }

    你将会添加下面的三个方法到ViewController中去处理album的三个管理操作:添加,删除和撤销。

    第一个方法是增加一个新的album:

    - (void)addAlbum:(Album *)album atIndex:(int)index  
       
    {  
       
        [[LibraryAPIsharedInstance] addAlbum:album atIndex:index];  
       
        currentAlbumIndex = index;  
       
        [selfreloadScroller];  
       
    }

      在这里你添加了一个album,设置它的当前的album的index,然后重新加载scroller.接下来删除方法:

      - (void)deleteAction  
         
      {  
         
          Album *deleteAlbum = [allAlbumsobjectAtIndex:currentAlbumIndex];  
         
          NSMethodSignature *sig = [selfmethodSignatureForSelector:@selector(addAlbum:atIndex:)];  
         
          NSInvocation*undoAction = [NSInvocationinvocationWithMethodSignature:sig];  
         
          undoAction.target = self;  
         
          [undoAction setSelector:@selector(addAlbum:atIndex:)];  
         
          [undoAction setArgument:&deleteAlbumatIndex:2];  
         
          [undoAction setArgument:¤tAlbumIndexatIndex:3];  
         
          [undoAction retainArguments];  
         
          [undoStackaddObject:undoAction];  
         
            
         
          [[LibraryAPIsharedInstance] deleteAlbumAtIndex:currentAlbumIndex];  
         
            
         
          [selfreloadScroller];  
         
            
         
          [toolBar.items[0] setEnabled:YES];  
         
      }

      在上面的这些代码里面有一些新的有趣的特性,所以解析一下:

      1.    获得要删除的album,

      2.    定义一个NSMethodSignature类型去创建一个NSInvocation,它将用于去在用户决定撤销一个删除时做和删除相
      反的操作。这个NSInovation需要知道三个事情:The
      selector(发送的消息),目标:((发送给谁)和发送的消息的一些参数。在这个例子里,消息时发送给删除的相反方,因为当你撤销一个删除操作,你
      需要将它们重新添加这个删除的album。、

      3.    当这个undoAction被创建后你将它添加到undoStack中,这个动作将会被添加到一个数组的末尾,正像一个普通的堆栈一样。

      4.    使用LibraryAPI去从数据结构中去删除album然后重新加载scroller。

      5.    因为在undoStack中有了一个动作,所以你需要去将undo按钮使能。

      注意:当你使用NSInvocation,你需要去记住下面的三个点:
      1. 参数必须通过指针来传递。

      2.参数起始于index 2,因为0和1是保留给target 和action用的。

      3. 如果这些参数有可能被销毁(dealocate),你应该使用retainArguments.

      最后添加下面的代码用于撤销:

      - (void)undoAction  
         
      {  
         
          if ([undoStackcount] > 0) {  
         
              NSInvocation*undoAction = [undoStacklastObject];  
         
              [undoStackremoveLastObject];  
         
              [undoActioninvoke];  
         
          }elseif( [undoStackcount] == 0){  
         
              [toolBar.items[0] setEnabled:NO];  
         
          }  
         
      }

        这个撤销操作会pops堆栈中的最后一个对象。这个对象永远是NSInvocation类型的而且可以通过调用invoke被激活。这回激活你你先
        前在album被删除时创建的命令,然后添加背删除的album到album列表中。因为你也可以删除在你撤销后最后一个对象,所以你需要判断这个栈是否
        时空的,如果是的话那么将undo按钮禁止交互。编译和运行你的app去特使这个undo 机制。删除这个album然后点击撤销操作去看看效果。

        还有两种设置模式没用将它们应用在这个app中,但是也是很重要的:抽象工厂模式和责任链模式。但官方文档去扩展你的设计模式水平

        在这个教程你已经看到怎么样去将发挥ios的设计模式的威力用很简单和耦合性地的方式去处理很复杂的任务。你已经学习了很多关于ios设计模式的概念:MVC, 但里,代理,协议,外观,贯彻着,备忘录,命令。

        你最后的代码是耦合性很低的,可重用的且可读性该,如果其他开饭看你的代码它会立刻明白这是怎么回事和每个类的作用。

        关键不是使用设计模式去写你的每一行代码而是当你在解决一个困难的问题特别是在设计应用的早期的时候意识到使用什么设计模式。它会让你的开发工作更容易,代码更高效。

        时间: 2024-10-13 10:37:39

        命令模式:的相关文章

        5.5 进入编辑模式 5.6 vim命令模式 5.7 vim实践

        5.5 进入编辑模式 5.6 vim命令模式 5.7 vim实践 扩展 vim的特殊用法 http://www.apelearn.com/bbs/thread-9334-1-1.html vim常用快捷键总结 http://www.apelearn.com/bbs/thread-407-1-1.html vim快速删除一段字符 http://www.apelearn.com/bbs/thread-842-1-1.html vim乱码 http://www.apelearn.com/bbs/thr

        Ubuntu命令模式基础

        Ubuntu是一个自由.开源.基于Debian的Linux发行版.在ubuntu的基础上,又衍生其它各具特色的Linux发行版.首先是一个操作系统,操作系统用于管理电脑硬件.要发挥出电脑的作用,还得依靠安装各种应用软件. 其相关的简单命令如下: (1)查看当前文件夹下的目录 ①.ls (list的缩写)命令用于列出文件和目录.默认上,他会列出当前目录的内容.带上参数后,可以以不同的方式显示.如图: ls命令可以列出当前目录的内容.dir命令是ls命令的一个别名,也是directory的缩写.通常

        【游戏设计模式】之二 实现撤消重做、回放系统的神器:命令模式

        本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/52663057 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 这篇文章将与大家一起探索游戏开发中命令模式的用法. 命令模式的成名应用是实现诸如撤消,重做,回放,时间倒流之类的功能.如果你想知道<Dota2>中的观战系统.<魔兽争霸3>中的录像系统.<守望先锋>

        命令模式

        1.命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化:对请求排列或记录请求日志,以及支持可以撤销的操作. 2.优点:(1).他能比较容易的设计一个命令队列:(2).在需要的情况下,比较容易的将命令记入日志:(3).允许接收请求的一方决定是否否决请求:(4).可以容易地实现对请求的撤销和重做:(5).由于加进新的具体命令类不影响其它类,因此增加新的具体命令很容易.(6).把请求一个操作的对象与指导怎么执行操作对象分隔开. 3.注意:不要为代码添加基于猜测的.实际不需要的

        【设计模式】 模式PK:命令模式VS策略模式

        1.概述 命令模式和策略模式的类图确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的意图是封装算法,它认为"算法"已经是一个完整的.不可拆分的原子业务(注意这里是原子业务,而不是原子对象),即其意图是让这些算法独立,并且可以相互替换,让行为的变化独立于拥有行为的客户:而命令模式则是对动作的解耦,把一个动作的执行分为执行对象(接收者角色).执行行为(命令角色),让两者相互独立而不相互影响. 我们从一个相同的业务需

        设计模式—命令模式

        1 概述 将一个请求封装为一个对象(即我们创建的Command对象),从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤销的操作. 2 解决的问题 在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录.撤销或重做.事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适. 3 模式中的角色 3.1 抽象命令(Command):定义命令的接口,声明执行的方法. 3.2 具体命令(ConcreteCommand):具体命令,实现要执

        javascript设计模式详解之命令模式

        每种设计模式的出现都是为了弥补语言在某方面的不足,解决特定环境下的问题.思想是相通的.只不过不同的设计语言有其特定的实现.对javascript这种动态语言来说,弱类型的特性,与生俱来的多态性,导致某些设计模式不自觉的我们都在使用.只不过没有对应起来罢了.本文就力求以精简的语言去介绍下设计模式这个高大上的概念.相信会在看完某个设计模式之后有原来如此的感慨. 一.基本概念与使用场景: 基本概念: 将请求封装成对象,分离命令接受者和发起者之间的耦合. 命令执行之前在执行对象中传入接受者.主要目的相互

        设计模式完结(14)-- 命令模式 --- 请求发送者与接收者解耦

        起连接作用:  类似开关   和  电器  之间的   电线 请求发送者与接收者解耦,  引入命令类 abstract class Command { public abstract void execute(); } class Invoker { private Command command; //构造注入 public Invoker(Command command) { this.command = command; } //设值注入 public void setCommand(Co

        命令模式(Command Pattern)

        命令模式:将“请求”封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也支持可撤销的操作. 模式类图: 下面举一个具体的例子: 有一个遥控器类RemoteControl,它可以控制Light类的行为,一个Command命令接口,两个实现Command接口的具体命令,分别实现开灯.关灯命令. 客户Client在使用这个遥控器的时候,先实例化一个RemoteControl类,如果它要开灯,那么就实例化LightOnCommand具体命令,将要控制的Light对象传入,调用setC

        设计模式 之 命令模式

        命令模式强调的是“封装调用”,即把方法调用封装起来.通过封装方法调用,我们可以把运算块封装成型,所以调用该运算的对象不需要关心事情是如何运行的,他们只需要知道如何使用包装成型的方法来完成它就可以了.通过封装方法调用,我们也可以做一些很聪明的事情,比如记录日志,或者重复使用这些封装来实现撤销. 我们通过下面这个例子 来了解命令模式:我们要设计一个家电自动化遥控器,这个遥控器具有多个可编程的插槽(每个插槽可以指定到一个不同的家电设备),每个插槽都对应一对开关按钮,整个遥控器还具备一个整体的撤销按钮,