Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1523997
  • 博文数量: 465
  • 博客积分: 8915
  • 博客等级: 中将
  • 技术积分: 6365
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-30 15:05
文章分类

全部博文(465)

文章存档

2017年(33)

2016年(2)

2015年(4)

2014年(29)

2013年(71)

2012年(148)

2011年(178)

分类: 嵌入式

2012-11-07 09:14:49

    你已经看到处理分数的方法如何通过名称直接访问两个实例变量numerator和denominator。事实上,实例方法总是可以直接访问它的实例变量的。然而,类方法则不能,因为它只处理本身,并不处理任何类实例(仔细想想)。但是,如果要从其他位置访问实例变量,例如,从main函数内部来访问,该如何实现?在这种情况下,不能直接访问这些实例变量,因为它们是隐藏的。将实例变量隐藏起来的这种做法实际上涉及一个关键概念——“数据封装”。它使得编写定义的人在不必担心程序员(即类的使用者)是否破坏类的内部细节的情况下,扩展和修改其定义。数据封装提供了程序员和其他开发者之间的良好隔离层。

       通过编写特殊方法来检索实例变量的值,可以用一种新的方式来访问它们。编写setNumerator:setDenominator:方法用于给Fraction类的两个实例变量设定值。为了获取这些实例变量的值,我们需要编写新的方法。例如,创建两个名为numeratordenominator的新方法,用于访问相应的Fraction实例变量,这些实例是消息的接收者。结果是对应的整数值,你将返回这些值。以下是这两个新方法的声明:

–(int) numerator;

–(int) denominator;

下面是定义:

–(int) numerator

{

   return numerator;

}

 

–(int) denominator

{

   return denominator;

}

注意,它们访问的方法名和实例变量名是相同的,这样做不存在任何问题(虽然似乎有些奇怪)。事实上,这是很常见的情况。代码清单3-4用来测试这两个新方法。

代码清单3-4

// 访问实例变量的程序 – cont'd

 

#import

 

//---- @interface 部分 ----

 

@interface Fraction: NSObject

 

-(void) print;

-(void) setNumerator: (int) n;

-(void) setDenominator: (int) d;

-(int) numerator;

-(int) denominator;

 

@end

 

//---- @implementation 部分 ----

 

@implementation Fraction

{

   int  numerator;

   int  denominator;

}

 

-(void) print

{

   NSLog (@"%i/%i", numerator, denominator);

}

 

-(void) setNumerator: (int) n

{

    numerator = n;

}

 

-(void) setDenominator: (int) d

{

    denominator = d;

}

 

-(int) numerator

{

    return numerator;

}

 

-(int) denominator

{

    return denominator;

}

 

@end

 

//---- program 部分 ----

 

int main (int argc, char *argv[])

{

   @autoreleasepool {

      Fraction  *myFraction = [[Fraction alloc] init];

 

      // 设置分数为1/3

 

      [myFraction setNumerator: 1];

      [myFraction setDenominator: 3];

 

      // 使用两个新的方法显示分数

 

      NSLog (@"The value of myFraction is: %i/%i",

           [myFraction numerator], [myFraction denominator]);

    }

 

    return 0;

}

 

代码清单3-4  输出

The value of myFraction is 1/3

 

NSLog语句显示发送给myFraction:的两条消息的结果,第一条消息检索numerator的值,第二条则检索denominator的值。

NSLog (@"The value of myFraction is: %i/%i",

    [myFraction numerator], [myFraction denominator]);

在第一条消息调用时,numerator消息会发送给Fraction类的对象myFraction。在这个方法中,分数中numerator的实例变量的值被返回。记住,方法执行的上下文环境就是接收到消息的对象。当访问numerator方法并且返回numerator实例变量值的时候,会取得myFraction的分子并返回,返回的整数传入NSLog,从而显示出来。第二条消息调用时,denominator方法会被调用并返回myFraction的分母,它仍通过NSLog显示。

顺便说一下,设置实例变量值的方法通常总称为设值方法(setter),而用于检索实例变量值的方法叫做取值方法(getter)。对Fraction而言,setNumerator:和setDenominator:是设值方法,numeratordenominator是取值方法。取值方法和设值方法通常称为访问器(accessor)方法。

确定你已经理解了设值方法和取值方法的不同。设值方法不会返回任何值,因为其主要目的是将方法参数设为对应的实例变量的值。在这种情况下并不需要返回值。另一方面,取值方法的目的是获取存储在对象中的实例变量的值,并通过程序返回发送出去。基于此目的,取值方法必须返回实例的值作为return的参数。

你不能在类的外部编写方法直接设置或获取实例变量的值,而需要编写设值方法和取值方法来设置或获取实例变量的值,这便是数据封装的原则。你必须通过使用一些方法来访问这些通常对“外界”隐藏的数据。这种做法集中了访问实例变量的方式,并且能够阻止其他一些代码直接改变实例变量的值。如果可以直接改变,会让程序很难跟踪、调试和修改。

这里还应指出,还有一个名为new的方法可以将allocinit的操作结合起来。因此,程序行

Fraction *myFraction = [Fraction new];

可用于创建和初始化新的Fraction。但用两步来实现创建和初始化的方式通常更好,这样可以在概念上理解正在发生两个不同的事件:首先创建一个对象,然后对它初始化。

 

 

本文节选自《Objective-C 程序设计(4)

电子工业出版社出版

[]Stephen G. Kochan(斯蒂芬·G·科昌)著

林冀  范俊朱奕欣译

阅读(507) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~