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


        你已经看到处理分数的方法如何通过名称直接访问两个实例变量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 <Foundation/Foundation.h>

     

    //---- @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·科昌)著

    林冀  范俊朱奕欣译

  • 相关阅读:
    内存管理工具
    c语言目录操作总结
    重写strstr、strcpy、memcpy、memset、atof算法
    统计编码量工具
    hdu4348
    bzoj4358: permu
    bzoj2658: [Zjoi2012]小蓝的好友(mrx)
    bzoj2657: [Zjoi2012]旅游(journey)
    bzoj3583: 杰杰的女性朋友
    bzoj3673 bzoj3674可持久化并查集
  • 原文地址:https://www.cnblogs.com/broadview/p/2758155.html
Copyright © 2020-2023  润新知