Objective-C-2.0程序设计-第11章-分类和协议_第1页
Objective-C-2.0程序设计-第11章-分类和协议_第2页
Objective-C-2.0程序设计-第11章-分类和协议_第3页
Objective-C-2.0程序设计-第11章-分类和协议_第4页
Objective-C-2.0程序设计-第11章-分类和协议_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Objective-C-2.0程序设计-第11章-分类和协议第第11章章 分类和协议分类和协议第第11章章 分类和协议分类和协议合成对象11.3协议11.2分类11.111.1 分类 有时候在处理类定义时,可能想要为其添加一些新方法。实用解决方案是:分类。分类提供了一种简单的方式,用它可以将类的定义模块化到相关方法的组或分类中。它还提供了扩展现有类定义的简便方式,并且不必访问类的源代码,也无需创建子类。分类是一个功能强大且简单的概念。 首先展示如何为Fraction类添加新分类,以处理基本的四则数学运算。首先,展示原始的Fraction接口部分:#import #import / Define

2、 the Fraction classinterface Fraction : NSObjectproperty int numerator, denominator;-(void) setTo: (int) n over: (int) d;-(Fraction *) add: (Fraction *) f;-(void) reduce;-(double) convertToNum;-(void) print;end11.1 分类 然后从接口部分删除add:方法,并将其添加到新分类,同时添加其他三种要实现的数学运算。新MathOps分类的接口部分应该如下所示:#import “Fraction

3、.h”interface Fraction (MathOps)-(Fraction *) add: (Fraction *) f;-(Fraction *) mul: (Fraction *) f;-(Fraction *) sub: (Fraction *) f;-(Fraction *) div: (Fraction *) f;end 注意,这既是接口部分的定义,也是现有接口部分的扩展。因此,必须包括原始接口部分,这样编译器就知道Fraction类。 在#import之后,有下面这一行:interface Fraction (MathOps)告诉编译器你正在为Fraction类定义新的分类

4、,而且它的名称为MathOps。注意此处没有列出Fraction的父类,因为编译器已从中知道此内容。11.1 分类 可以将所有方法的定义放在一个实现部分。也就是,可以在一个实现文件中定义接口部分中的所有方法,以及MathOps分类中的所有方法。或者在单独的实现部分定义分类的方法。在这种情况下,这些方法的实现部分还必须找出方法所属的分类。与接口部分一样通过将分类名称包括在类名称之后的圆括号中来确定方法所属的分类,如下所示:implementation Fraction (MathOps)/ code for category methods.end 在代码清单11-1中,新的MathOps分类的

5、接口和实现部分组合在一起,连同测试例程都放在一个文件中。11.1 分类 代码清单11-1-#import “Fraction.h”interface Fraction (MathOps)-(Fraction *) add: (Fraction *) f;-(Fraction *) mul: (Fraction *) f;-(Fraction *) sub: (Fraction *) f;-(Fraction *) div: (Fraction *) f;end11.1 分类implementation Fraction (MathOps)-(Fraction *) add: (Fraction

6、 *) f/ To add two fractions:/ a/b + c/d = (a*d) + (b*c) / (b * d)Fraction *result = Fraction alloc init;int resultNum, resultDenom;resultNum = (numerator * f.denominator) +(denominator * f.numerator);resultDenom = denominator * f.denominator;result setTo: resultNum over: resultDenom;return result;11

7、.1 分类-(Fraction *) sub: (Fraction *) f/ To sub two fractions:/ a/b - c/d = (a*d) - (b*c) / (b * d)Fraction *result = Fraction alloc init;int resultNum, resultDenom;resultNum = (numerator * f.denominator) -(denominator * f.numerator);resultDenom = denominator * f.denominator;result setTo: resultNum o

8、ver: resultDenom;return result;11.1 分类-(Fraction *) mul: (Fraction *) fFraction *result = Fraction alloc init;over: denominator * f.denominator;return result;-(Fraction *) div: (Fraction *) fFraction *result = Fraction alloc init;over: denominator * f.numerator;return result;end11.1 分类int main (int

9、argc, char *argv)NSAutoreleasePool * pool = NSAutoreleasePool alloc init;Fraction *a = Fraction alloc init;Fraction *b = Fraction alloc init;Fraction *result;a setTo: 1 over: 3;b setTo: 2 over: 5;a print; NSLog (” +”); b print; NSLog (”-”);result = a add: b;result print;NSLog (”n”);result release;11

10、.1 分类a print; NSLog (” -”); b print; NSLog (”-”);result = a sub: b;result print;NSLog (”n”);result release;a print; NSLog (” *”); b print; NSLog (”-”);result = a mul: b;result print;NSLog (”n”);result release;a print; NSLog (” /”); b print; NSLog (”-”);result = a div: b;result print;NSLog (”n”);resu

11、lt release;a release;b release;pool drain;return 0;11.1 分类 再次注意,以下语句在Objective-C语言中是合法的:a div: b print;在代码清单11-1中有这项操作,但需要执行这个中间赋值,这样可以获得结果Fraction,并随后释放它的内存,否则,每次对分数执行数学运算,程序都会泄露一些内存。关于分类的一些注意事项 首先,尽管分类可以访问原始类的实例变量,但是它不能添加自身的任何变量。如果需要添加变量,可以考虑创建子类。 另外,分类可以重载该类中的另一个方法,但是通常认为这种做法是拙劣的设计习惯。其一,重载了一个方法之后

12、,再也不能访问原来的方法。因此,必须小心地将被重载方法中的所有功能赋值到替换方法中。如果确实需要重载,正确的选择可能是创建子类。 如果喜欢,可以拥有许多分类,只要遵守此处指出的规则。如果一个方法定义在多个分类中,该语句不会指定使用哪个分类。 第第11章章 分类和协议分类和协议合成对象11.3分类11.1协议11.211.2 协议 协议是多个类共享的一个方法列表。协议中列出的方法没有相应的实现。协议提供一种方式来使用指定的名称定义一组多少有点相关的方法。这些方法通常有文档说明,所以你知道它们将如何执行,因此,如果需要,可以在自己的类定义中实现它们。 如果决定实现特定协议的所有方法,也就意味着要遵

13、守或者采用这项协议。 定义一个协议很简单:只要使用protocol指令,之后是你给出的协议的名称。然后和处理接口部分一样,声明一些方法。 下面是在标准的Foundation头文件中定义NSCopying协议的方式:protocol NSCopying- (id)copyWithZone: (NSZone *)zone;end11.2 协议 如果你的类采用NSCopying协议,则必须实现名为copyWithZone:的方法。通过在interface行的一对尖括号内列出协议名称,可以告知编译器你正在采用一个协议,这项协议的名称放在类名和它的父类名称之后,如下所示:interface Addres

14、sBook: NSObject 系统已经知道以前为这个协议定义的方法,所以不必在接口部分声明这些方法,但是,要在实现部分定义它们。 如果你的类采用多项协议,只需把它们都列在尖括号中,用逗号分开:interface AddressBook: NSObject 如果定义了自己的协议,则不必由自己实现它。但是,这就告诉其他程序员:如果要采用这项协议,则必须实现这些方法。这些方法可以从超类继承。这样,如果一个类遵守NSCopying协议,则它的子类也遵守NSCopying协议。11.2 协议 如果希望继承你的类的用户实现一些方法,则可以使用协议定义这些方法。可以为你的GraphicObject类定义一

15、个Drawing协议,并且可以在其中定义paint,erase和outline方法,如下:protocol Drawing-(void) paint;-(void) erase;optional-(void) outline;end 作为GraphicObject类的创建者,你不必实现这些方法,但是需要制定一些方法,要求从GraphicObject创建子类的人实现这些方法,以便符合它要创建的绘图对象的标准。11.2 协议 可以使用conformToProtocol:方法检测一个对象是否遵循某项协议。例如,如果有个名为currentObject的对象,并且想要查看它是否遵循Drawing协议,可

16、以向它发送绘图消息,可以如下编写:id currentObject;.if (currentObject conformsToProtocol: protocol (Drawing) = YES)/ Send currentObject paint, erase and/or outline msgs.这里使用的专用protocol指令用于获取一个协议名称,并产生一个Protocol对象,conformsToProtocol:方法期望这个对象作为它的参数。11.2 协议 通过在类型名称之后的尖括号中添加协议名称,可以借助编译器的帮助来检查变量的一致性,如下所示:id currentObject

17、;这告知编译器currentObject将包含遵守Drawing协议的对象。如果向currentObject指派静态类型的对象,这个对象不遵守Drawing协议,编译器将发出一条警告消息,如下所示:warning: class Square does not implement the Drawing protocol 这里存在一项编译器校验,所以向currentObject指派一个id变量不会产生这条信息,因为编译器无法知道存储在id变量中的对象是否遵守Drawing协议。 如果这个变量保存的对象遵守多项协议,则可以列出多项协议,如下代码所示:id myDocument;11.2 协议 定义

18、一项协议时,可以扩展现有协议的定义,所以以下协议定义protocol Drawing3D 说明Drawing3D协议也采用了Drawing协议。 最后,分类也可以采用一项协议,如下所示:interface Fraction (Stuff) 此处,Fraction拥有一个分类Stuff,这个分类采用了NSCopying和NScoding协议。 和类名一样,协议名必须是唯一的。11.2 协议非正式协议 非正式协议实际上是一个分类,列出了一组方法但并没有实现他们。每个人都继承相同的根对象,因此非正式分类通常是为根类定义的。有时,非正式协议也称作抽象协议。 如果查看头文件,可能会发现如下所示的一些方法

19、声明:interface NSObject (NSComparisonMethods)- (BOOL)isEqualTo:(id)object;- (BOOL)isLessThanOrEqualTo:(id)object;- (BOOL)isLessThan:(id)object;- (BOOL)isGreaterThanOrEqualTo:(id)object;- (BOOL)isGreaterThan:(id)object;- (BOOL)isNotEqualTo:(id)object;- (BOOL)doesContain:(id)object;- (BOOL)isLike:(NSStr

20、ing *)object;- (BOOL)isCaseInsensitiveLike:(NSString *)object;end11.2 协议 这些代码为NSObject类定义了一个名为NSComparisonMethods的分类。这项非正式协议列出了一组方法,可以将它们实现为协议的一部分。非正式协议实际上仅仅是一个名称下的一组方法。这在文档说明和模块化方法时,可能有所帮助。 声明非正式协议的类自己并不实现这些方法,并且选择实现这些方法的子类需要在它的接口部分重新声明这些方法,同时还要实现这些方法中的一个或多个。和正式协议不同,编译器不提供有关非正式协议的帮助; 如果一个对象采用正式协议,则

21、它必须遵守协议中的所有信息。这可以在运行时以及编译时强制执行。如果一个对象采用非正式协议,则它可能不需要采用此协议的所有方法,具体取决于这项协议。可以在运行时强制要求遵守一项非正式协议,但是在编译时不可以。第第11章章 分类和协议分类和协议协议11.2分类11.1合成对象11.311.3 合成对象合成对象 你已经学习了通过派生子类和分类等技术扩展类定义的几种方式。有另一项设计定义一个包含其他类的一个或多个对象的技术。这个新类的对象就是所谓的合成(composite)对象,因为它是由其他对象组成的。 比如,考虑第8章中定义的Square类。将这个类定义为Rectangle的子类,因为你知道正方形就是等边的矩形。定义子类时,它继承了父类的所有实例变量和方法。在一些情况下,这种做法不合适。例如,在父类中定义的一些方法可能不适合子类使用。Square类继承了Rectangle的setWidth:andHeig

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论