一、Cocoa设计模式
Cocoa环境的许多架构和机制都能够有效地使用设计模式:抽象设计可以解决特定环境中的重复问题。 本文描述了Cocoa中设计模式的主要实现,主要关注模型(Model) - 视图(View) - 控制器(Controller)和对象建模。 本章的主要目的是让您更深入地了解Cocoa的设计模式,并鼓励您在自己的软件项目中利用这些模式。
二、什么是设计模式?
设计模式是设计的模板,它可以在特定的上下文中解决一般的、重复出现的问题。它是一种抽象工具,在建筑、工程和软件开发等领域都很有用。下面的部分总结了设计模式是什么,解释了为什么它们对于面向对象设计很重要,并讨论了一个示例设计模式。
三、Cocoa如何改变设计模式
可以在OS X和ios版本中找到适用于Cocoa的设计模式。 基于模式的机制和体系结构在Cocoa框架和Objective-C 的 runtime 和语言中很常见。Cocoa经常把自己独特的旋律放在一个模式上,因为它的设计受语言能力或现有体系结构等因素的影响。
本节包含大多数设计模式的摘要,这些设计模式是在“ 设计模式:可重用面向对象软件的元素”中编目的。 每个部分不仅总结了模式,还讨论了Cocoa的实现。 只列出Cocoa实现的模式,以下各节中的模式描述都与特定的Cocoa上下文有关。Cocoa设计模式的实现有多种形式。 以下部分中描述的一些设计(如协议和类别)是 Objective-C语言的特性。 在一些情况下,“模式实例”是在一个类或一组相关类(例如,类集群和单例类)中实现的。 在另一些情况下,模式适应是一个主要的框架体系结构,例如响应者链。 一些基于模式的机制几乎可以“免费”获得,而另外一些机制则需要做一些工作。 即使Cocoa没有实现一个模式,当情况需要时,你自己可以这样实现; 例如,对象组合(Decorator模式)通常比继承类的行为更好。
两个设计模式保留给后面的部分,模型 - 视图 - 控制器(MVC)和对象建模。 MVC是一种复合或聚合模式,这意味着它基于几种目录模式。 对象建模在“四人帮”目录中没有对应,而是源于关系数据库的领域。 然而MVC和对象建模也许是Cocoa中最重要,最普遍的设计模式,在很大程度上它们是相互关联的模式。 它们在包括绑定,撤销管理,脚本和文档体系结构在内的多种技术的设计中起着至关重要的作用。
四、案例分析:前台设计模式
前台设计模式是一种混合模式。虽然它没有出现在“四人帮”的书,它结合了命令,备忘录的元素,和本文中描述的代理设计模式。这也是蹦床模式(Trampoline pattern)的一个变种(其中还没有出现在书中);在这种模式中,一个事件最初是由一个蹦床对象接收,这样叫因为它立刻反弹,或重定向,处理到目标对象的事件。当你需要反弹继续处理另一个执行上下文,可以通过前台设计模式。当你观察一个通知,或者实现一个块处理程序,或响应一个消息,你要确保你的代码在适当的执行上下文中执行,可以实现前台模式改变所必须做的工作,执行上下文。前台模式,在反弹任务数据处理之前,甚至可以执行一些过滤或合并输入数据。例如,可以收集数据分批进入,然后在区间调度这些批次做其他处理。
一种常见的情况,接待员模式是有用的键值观察。对一个模型对象的属性的值的变化是通过KVO通知传达给观察者。然而,一个模型对象的变化可以在后台线程上发生。这个结果在一个线程不匹配,因为一个模型对象的状态变化通常会导致更新用户界面,这些都必须在主线程中发生。在这种情况下,你想重定向KVO通知主线程。
KVO通知调用由观察者实现的observeValueForKeyPath:ofObject:change:context:方法。如果改变的属性发生在辅助线程,该observeValueForKeyPath:ofObject:change:context:在同一个线程执行的代码。在这个模式中有中央的对象,前台接待员,作为一个线程的中介。下图说明,接待对象被分配作为一个模型对象的属性的观察。前台实现observeValueForKeyPath:ofObject:change:context:将收到的通知在辅助线程上的另一个执行上下文的主要操作队列,在这种情况下。属性变化时,接待员收到一个KVO通知。接待员立即增加一块操作的主要操作队列;块包含指定的更新用户界面的适当代码。
定义一个接待员类具有元素需要添加本身作为一个观察者的属性,然后将一个KVO通知到一个更新的任务。因此,它必须知道它的观察对象,该对象的属性,这是观察,什么更新任务执行,什么队列执行它。下面代码显示初始声明RCReceptionist类及其实例变量。
RCTaskBlock实例变量是下面这样的block对象
observeValueForKeyPath:ofObject:change:context: 方法的参数是相似的,参数类声明单例类工厂方法,rctaskblock对象是一个参数:
它实现了该方法分配传入的值来实例化被接待员对象创建的实例变量,对象为模型对象属性的一个观察者
注意代码复制的block对象而不是retaining它。因为bock可能是在栈上创建的,它必须被复制到堆,,KVO通知时它得存在于内存中。
最后,observeValueForKeyPath:ofObject:change:context:
方法参数的实现:
这个代码在给定的运行队列进行简单的查询任务,通过被观察对象的task block,为改变属性的关键路径,和字典包含新value。任务是封装在一个NSBlockOperation对象执行任务队列。
客户端对象提供的block代码,更新用户界面创建一个接待员对象时,如下面代码,请注意,创建的接待对象时,客户端传给在运行队列的数据block被执行,在这种情况下的主要操作队列。
五、引入该设计模式后对系统架构和代码结构带来了哪些好处;
优点:
从而使得各自的变化都不会影响另一边的变化。
缺点:
依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
适用场景:
当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。
一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将
这两者封装在独立的对象中使它们各自独立地改变和复用。