zoukankan      html  css  js  c++  java
  • 实例变量的访问及数据封装

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

    林冀  范俊朱奕欣译

  • 相关阅读:
    Realtime crowdsourcing
    maven 常用插件汇总
    fctix
    sencha extjs4 command tools sdk
    首次吃了一颗带奶糖味的消炎药,不知道管用不
    spring mvc3 example
    ubuntu ati driver DO NOT INSTALL recommand driver
    yet another js editor on windows support extjs
    how to use springsource tools suite maven3 on command
    ocr service
  • 原文地址:https://www.cnblogs.com/broadview/p/2758155.html
Copyright © 2011-2022 走看看