Cocoa设计模式(iOS常用设计模式) Cocoa Design Patterns

Cocoa设计模式

Cocoa环境的许多架构和机制都能够有效地使用设计模式:抽象设计可以解决特定环境中的重复问题。 本文描述了Cocoa中设计模式的主要实现,主要关注模型(Model) – 视图(View) – 控制器(Controller)和对象建模。 本章的主要目的是让您更深入地了解Cocoa的设计模式,并鼓励您在自己的软件项目中利用这些模式。

什么是设计模式/h2>

设计模式是设计的模板,它可以在特定的上下文中解决一般的、重复出现的问题。它是一种抽象工具,在建筑、工程和软件开发等领域都很有用。下面的部分总结了设计模式是什么,解释了为什么它们对于面向对象设计很重要,并讨论了一个示例设计模式。

一个问题的解决方案

作为开发人员,您可能已经熟悉面向对象编程中的设计模式概念。 他们首先由Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides(通常被称为“四人帮”)设计模式:可重用面向对象软件的元素进行了权威性的描述和编目。 这本书最初发表于1994年,不久之后还有其他书籍和文章,进一步探讨和阐述了面向对象系统中的设计模式。

设计模式的简洁定义是“对上下文中的问题的解决方案”。让我们通过反向解释这个短语来解析这个问题。 上下文是该模式适用的反复出现的情况。 问题是你在这个上下文中试图达到的目标,以及上下文所带来的任何约束。 解决方案就是你所追求的目标:通用的上下文设计,达到目标并解决约束。

设计模式将具体设计结构的关键方面抽象出来,这已经被证明是有效的。 该模式有一个名称,并标识参与该模式的类和对象及其职责和协作。 它还列出了后果(成本和收益)以及该模式可以应用的情况。 设计模式是特定设计的一种模板或指南; 从某种意义上讲,具体的设计就是一种模式的“实例化”。 设计模式并不是绝对的。 在如何应用它们方面有一定的灵活性,通常诸如编程语言和现有体系结构的东西可以决定如何应用模式。

设计的几个主题或原则影响设计模式。 这些 设计原则是构建面向对象系统的经验法则,如“封装不同系统结构的各个方面”,“编程是为了接口而不是实现”,它们表达了重要的见解。 例如,如果您隔离系统中各部分并将其封装起来,那么它们可以独立于系统的其他部分而变化,特别是如果您为它们定义了与实现细节无关的接口。 您稍后可以更改或扩展这些可变部分,而不会影响系统的其他部分。 因此,您可以消除依赖性并减少部件之间的耦合,从而使系统变得更加灵活和易于更改。

在编写软件时,设计模式是一个重要的考虑因素。 如果您在程序设计中找到,适应和使用模式,那么程序(包括它所包含的对象和类)将更具可重用性,可扩展性和更容易随着未来需求的变化而改变。 而且,基于设计模式的程序通常比不考虑设计模式的程序更加优雅和高效,因为它们只需要更少的代码就能实现相同的目标。

举例:命令模式(Command Pattern)

“四人帮”的大部分书籍都是由一个设计模式目录组成的。 它按范围(类或对象)和目的(创建,结构或行为)对目录中的模式进行分类。 目录中的每个条目讨论设计模式的意图,动机,适用性,结构,参与者,合作,后果和实现。 其中一个条目是 命令模式(一种对象行为模式)。

本书陈述Command模式的意图是“将请求封装为一个对象,从而允许您使用不同的请求参数化客户端,排队或记录请求,并支持可撤销操作”。模式将发送消息的对象与接收和评估这些消息的对象分隔开。 消息的发起者(客户端)通过将特定接收者上的一个或多个动作绑定在一起来封装请求。 封装的消息可以在对象之间传递,放置在队列中或以其他方式存储以用于稍后的调用,并且动态地修改以改变接收器或消息参数。 下图显示了该模式的结构图。

Cocoa设计模式(iOS常用设计模式) Cocoa Design Patterns

视图层次结构是在绘图和事件处理中起作用的结构体系结构。 一个视图有两个边界矩形,它的框架和边界,这些矩形会影响视图的图形操作。 框架是外部边界; 它将视图定位在其超级视图的坐标系中,定义其大小,并将绘图剪辑到视图的边缘。 边界(内部边界矩形)定义视图自身绘制的曲面的内部坐标系。

当窗口系统要求窗口准备显示时,要求超级视图在其子视图之前进行渲染。 当你发送一些消息到一个视图 – 例如,一个请求视图重绘自己的消息 – 消息传播到子视图。 因此,您可以将视图层次结构的分支视为统一的视图。

响应者链也使用视图层次来处理事件和动作消息。

使用和限制

无论是以编程方式还是使用Interface Builder将视图添加到其他视图,都可以创建或修改视图层次结构。 AppKit框架自动处理与视图层次关联的所有关系。

装饰器

装饰设计模式动态地将额外的责任附加到对象上。 装饰器为扩展功能提供了子类化的灵活替代方案。 与子类化一样,修饰器模式的适应性允许您在不修改现有代码的情况下合并新的行为。 装饰器包装了它们扩展行为的类的一个对象。 它们实现与它们所包装的对象相同的接口,并在将任务委托给包装对象之前或之后添加它们自己的行为。 Decorator模式表达了这样的设计原则:类应该是可以拓展的,而不需要修改类。

常规注释

装饰者是一个对象组合模式,非常鼓励这样做。 但是,Cocoa提供了一些自己的类和机制(在下面的部分讨论)是基于装饰模式。 在这些实现中,扩展对象并不完全复制它所包装的对象的接口,并且这些实现使用不同的技术来进行接口共享。

Cocoa在其几个类的实现中使用了Decorator模式,包括 , ,和 。 后两个类是复合视图的例子,它将其他视图类的简单对象组合在一起,并协调它们的交互。

代理 (Delegation)

代理是一种机制,通过这种机制,宿主对象将一个弱引用(意味着它是一个简单的指针引用,而不是 retained)嵌入到另一个对象中,在需要输入任务时定期向代理发送消息。 宿主对象通常是一个“现成的”框架对象(比如 要么 对象)正在寻求完成一些事情,但只能以一种通用的方式来实现。 代理几乎总是一个自定义类的实例,与主机对象协调工作,在任务的某些点提供程序特定的行为( 见下图 )。 因此,委派可以修改或扩展另一个对象的行为,而无需进行子类化。

Cocoa设计模式(iOS常用设计模式) Cocoa Design Patterns

备忘录模式(Memento)

备忘录模式捕捉和外部化对象的内部状态,而不违反封装-使得对象可以恢复到这种状态后。备忘录模式保持关键对象外部的重要状态。

归档

将对象存档在一个程序中,随着这些对象的属性(属性和关系)到档案,可以存储在文件系统或过程或在网络之间传输。以字节存档了一个程序的对象图,保留对象的身份和他们之间的关系的一种体系结构无关的流。因为一个对象的类型及其数据存储对象解码字节流通常实例化的对象使用原来的编码相同的类。

使用和限制

一般来说,你想保存一些程序中想要保存状态的对象。模型对象几乎都属于这一类。写一个对象的档案进行编码和解码,通过解码从归档中读取那个对象。编码和解码是你使用对象执行的操作,最好使用密钥归档技术(你要调用的方法和类)。被编码和解码的对象必须符合协议;该协议的方法被调用时归档

属性列表序列化

属性列表是一个简单的,使用下面类对象结构序列化的对象图:, , , ,, .这些对象通常被称为属性列表对象。几个Cocoa框架类提供的方法来将这些属性列表对象和定义数据流记录的对象及其层次关系的特殊格式的内容。这个类提供的类方法,可以从XML格式或优化的二进制格式,序列化属性列表对象。

使用和限制

如果在对象图中的对象是简单的,属性列表序列化是一个灵活的,便携的,和足够的手段来捕捉和呈现对象及其状态。然而,这种形式的序列化有其局限性。它不保存对象完整的标识,只是一般的类型(数组,字典,字符串,等等)。因此,一个对象从属性列表恢复可能是一个与原来类不同的类。这是一个问题,当一个对象的可变性可以不同。属性列表序列化也不跟踪,对象中多次引用的对象,可能会导致多个实例在反序列化,在原来的对象图的一个实例。

Core Data

Core Data是Cocoa框架,定义了管理对象图,使他们持续的架构。正是这第二能力对象持久化使Core Data适应备忘录模式。

核心数据的设计也严重的影响了模型-视图-控制器和对象建模模式。

使用和限制

Core Data在企业应用的发开中非常有用,模型对象的复杂图必须定义,管理,和透明的归档和未归档和数据存储。
核心数据是特别有用的企业应用中的模型对象的复杂图必须定义,管理,和透明的归档和未归档和数据存储。Xcode开发环境包括项目模板和设计工具,来减少需要创建核心数据应用的两种类型的编程工作,那些基于文档和那些不是基于文档的数据。Interface Builder应用还包括可配置的库中的核心数据结构对象。

观察者(Observer)

观察者设计模式定义了对象之间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的通知并自动更新。观察者模式本质上是一个发布和订阅模型,它的主体及其观察员是松散耦合。观察和观察对象之间不需要知道对方就可以发生通信。

通知(Notifications)

Cocoa通知机制实现了一个基于观察者模式的消息一对多广播。在一个程序中的对象添加自己或其他对象的列表,有一个或多个通知观察者,其中每一个是由全局的字符串识别(通知的名字)。要通知其它对象,观察对象创建一个通知对象和推送到通知中心的对象。通知中心决定一个特定的通知观察者,通过消息将通知发送到他们。该方法通过通知消息调用必须符合一定的单参数签名。该方法的参数是通知对象,其中包含通知名,观察对象,和一个包含任何补充信息字典。

推送通知是一个同步程序。发布对象不重新控制到通知中心有广播通知所有的观察者。对于异步行为,你可以在通知队列中通知;控制立即返回到发布对象,当通知到达队列顶部时通知中心再广播。

定期通知,这些通过通知中心的广播只是进程内。如果你想给其他进程广播通知,您可以使用分布式通知中心及其相关的API。

使用和限制

你可以因为各种各样的原因使用通知,。例如,可以广播通知改变用户界面元素的显示信息,基于在程序的其他地方的某一事件。或者你可以用通知的方式确保目标文档中的文档窗口关闭前保存它们的状态。通知的目的是告知其他对象程序事件使他们能够作出适当的反应。

但对象接收通知的反应只有在已经发生的事件。这是和代理的显著差异。代理有机会拒绝或修改由委托对象提出的操作。另一方面,观察对象不能直接影响即将进行的操作。

通知类都是(通知对象),(推送通知和添加观察员),(队列化通知),和。许多Cocoa框架类发布通知后,任何对象都可以观察。

Key-Value Observing

KVO是一种机制,允许当其他对象的具体特性的变化时对象被通知。它是基于 非正式协议。观察到的属性可以是简单的属性,一个一关系,或一对多的关系。在模型视图控制器模式下,键值观察尤为重要,因为它使视图对象模型对象的观察通过控制器层的变化。因此,这是Cocoa的一个必不可少的绑定技术的组成部分。

Cocoa提供了一个默认“自动”的实施方法:给所有符合对象的属性的观察能力。

使用和限制

KVO是类似的通知机制,但在一些重要的方面不同。在键值观察没有中央的对象,提供所有观察员变更通知。相反,变化通知直接发送到观察对象。键值观察也直接关系到具体对象的属性值。另一方面,通知机制,更广泛的关注程序事件。

对象参与键值观察(KVO)必须KVO兼容即遵守一定的要求。对于自动观测,这需要符合要求的关键值编码(KVC依从性)和使用KVC的依从性的方法(即,访问器方法)。键值编码是一种机制(基于相关的非正式协议)自动获取和设置对象属性的值。

你可以通过禁用自动化KVO通知观察者通知,使用方法非正式的协议和相关的类执行手动通知。

代理(Proxy)

代理设计模式提供了一种替代,或占位符,为另一个对象来控制访问其他对象。使用这个模式来创建一个代表或代理,对象,控制访问另一个对象,这可能是远程的,复杂的创建,或需要保护。这种模式的结构类似于装饰模式却有不同的用途;装饰给对象添加行为,而代理控制对对象的访问。

NSProxy

类定义了对象作为其他对象的代理对象的接口,甚至对象还不存在。一个代理对象通常转发消息给它代表的对象,但它也可以响应消息,通过加载对象转变为它或代表。虽然是一个抽象类,它实现了协议和其他基本方法的根对象的预期;事实上,一个层次结构的基类,如类

具体的子类能够完成既定目标的代理模式,如昂贵的对象或作为安全哨兵懒实例化对象。,基础框架中一个具体子类,实现了一个远程代理,对于透明的分布式消息。对象是分布式对象结构的一部分。作为对其他进程或线程对象的代理,它们有助于使这些线程或进程的对象之间的通信。

对象,这是命令模式的一种适应体,也是分布式对象体系结构的一部分

使用和限制

Cocoa只有在分布式对象采用对象。这个NSProxy对象是具体的实例,是具体子类和。不仅可以使用分布式对象为进程消息(在相同的或不同的计算机)也可以用它来实现分布式计算和并行处理。如果你想使用代理对象的其他用途,如昂贵的资源或安全的创造,你要实现你自己的具体的子类

接待员(Receptionist)

前台设计模式是一种混合模式。虽然它没有出现在“四人帮”的书,它结合了命令,备忘录的元素,和本文中描述的代理设计模式。这也是蹦床模式(Trampoline pattern)的一个变种(其中还没有出现在书中);在这种模式中,一个事件最初是由一个蹦床对象接收,这样叫因为它立刻反弹,或重定向,处理到目标对象的事件。

当你需要反弹继续处理另一个执行上下文,可以通过前台设计模式。当你观察一个通知,或者实现一个块处理程序,或响应一个消息,你要确保你的代码在适当的执行上下文中执行,可以实现前台模式改变所必须做的工作,执行上下文。前台模式,在反弹任务数据处理之前,甚至可以执行一些过滤或合并输入数据。例如,可以收集数据分批进入,然后在区间调度这些批次做其他处理。

一种常见的情况,接待员模式是有用的键值观察。对一个模型对象的属性的值的变化是通过KVO通知传达给观察者。然而,一个模型对象的变化可以在后台线程上发生。这个结果在一个线程不匹配,因为一个模型对象的状态变化通常会导致更新用户界面,这些都必须在主线程中发生。在这种情况下,你想重定向KVO通知主线程。

前台设计模式的实践

KVO通知调用由观察者实现的方法。如果改变的属性发生在辅助线程,该在同一个线程执行的代码。在这个模式中有中央的对象,前台接待员,作为一个线程的中介。下图说明,接待对象被分配作为一个模型对象的属性的观察。前台实现将收到的通知在辅助线程上的另一个执行上下文的主要操作队列,在这种情况下。属性变化时,接待员收到一个KVO通知。接待员立即增加一块操作的主要操作队列;块包含指定的更新用户界面的适当代码。

Cocoa设计模式(iOS常用设计模式) Cocoa Design Patterns

定义一个接待员类具有元素需要添加本身作为一个观察者的属性,然后将一个KVO通知到一个更新的任务。因此,它必须知道它的观察对象,该对象的属性,这是观察,什么更新任务执行,什么队列执行它。下面代码显示初始声明RCReceptionist类及其实例变量。

RCTaskBlock实例变量是下面这样的block对象

observeValueForKeyPath:ofObject:change:context: 方法的参数是相似的,参数类声明单例类工厂方法,rctaskblock对象是一个参数:

它实现了该方法分配传入的值来实例化被接待员对象创建的实例变量,对象为模型对象属性的一个观察者

注意代码复制的block对象而不是retaining它。因为bock可能是在栈上创建的,它必须被复制到堆,,KVO通知时它得存在于内存中。

最后,方法参数的实现:

这个代码在给定的运行队列进行简单的查询任务,通过被观察对象的task block,为改变属性的关键路径,和字典包含新value。任务是封装在一个NSBlockOperation对象执行任务队列。

客户端对象提供的block代码,更新用户界面创建一个接待员对象时,如下面代码,请注意,创建的接待对象时,客户端传给在运行队列的数据block被执行,在这种情况下的主要操作队列。

单例(Singleton)

单例设计模式确保一个类只有一个实例,并提供一个访问它的全局访问点。这类跟踪它的唯一实例,可以确保没有其他实例可以被创建。单例类是适当的情况下,对于提供一个全球性的资源是有意义的一个对象。

框架类

几个Cocoa框架类是单例。他们包括NSFileManager,NSWorkspace,NSApplication以及在UIKit中,UIApplication。一个进程是限制这些类只有一个实例。当客户端请求一个实例的类,它获取一个共享实例,这是建立在第一次请求时懒创建的。

使用和限制

使用通过单例类返回的共享实例,和使用非单例类的一个实例没什么不同,只是你无法copying、retaining或者releasing它(有关方法重新实现零操作)。如果情况需要可以创建你自己的单例类

模板方法

模板方法设计模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类。模板方法模式让子类重新定义算法中的某些步骤而不改变算法的结构。

重写框架方法

模板方法模式是一个基本的Cocoa设计,而且面向对象框架是很普遍的。在Cocoa的模式让一个程序把自己的自定义组件为一个算法,但框架组件决定何时需要它们。Cocoa类的编程接口通常包括由子类重写方法。在运行时,框架调用这些所谓的通用方法在某些点的任务执行。一般的方法提供了一种用于自定义代码提供程序特定的行为和数据的任务执行和协调的框架类结构。

使用和限制

利用Cocoa改编的模板方法模式,你必须创建一个类的子类并重写这些方法,框架调用插入应用程序特定的输入方法是执行。如果你写自己的框架,你应该包括在设计模式。

来源:yofer张耀琦

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2017年11月10日
下一篇 2017年11月10日

相关推荐