3.7 实例变量的访问以及数据封装

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

通过编写特殊方法来检索实例变量的值,可以用一种新的方式来访问它们。例如,创建两个非常恰当地命名为numerator和denominator的方法,它们用来访问作为消息接收者的Fraction的相应实例变量。结果将是相应整数值,你将返回这些值。以下是这两个新方法的声明:


-(int)numerator;

-(int)denominator;


下面是定义:


-(int)numerator

{

return numerator;

}

-(int)denominator

{

return denominator;

}


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

代码清单3-4


//Program to access instance variables-contd

import<Foundation/Foundation.h>

//——@interface section——

@interface Fraction:NSObject

{

int numerator;

int denominator;

}

-(void)print;

-(void)setNumerator:(int)n;

-(void)setDenominator:(int)d;

-(int)numerator;

-(int)denominator;

@end

//——@implementation section——

@implementation Fraction

-(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 section——

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

{

NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];

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

//Set fraction to 1/3

[myFraction setNumerator:1];

[myFraction setDenominator:3];

//Display the fraction using our two new methods

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

[myFraction numerator],[myFraction denominator]);

[myFraction release];

[pool drain];

return 0;

}


代码清单3-4输出


The value of myFraction is 1/3


NSlog语句


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

[myFraction numerator],[myFraction denominator]);


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

顺便说一下,设置实例变量值的方法通常总的称为设置函数(setter),而用于检索实例变量值的方法叫做获取函数(getter)。对于Fraction类而言,setNumerator:和setdenominator:是设置函数,numerator和denominator是获取函数。

注意不久就会看到Objective-C 2.0一个很方便的特性,即允许自动创建设置函数方法和获取函数方法。

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


Fraction*myFraction=[Fraction new];


可用于分配和初始化新的Fraction。

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