zoukankan      html  css  js  c++  java
  • ObjectiveC中的继承与复合技术(转)

    今天学习了Objective-C中有关类继承的知识。先纪录如下:

    1)OOP编程中有两个技术 用于描述类与类或对象与对象之间的关系;一个是继承 另一个是复合。
    2)在Objective-C中每个子类只能有一个超类,这一点与c++不同。
    3)方法调度程序
          该调度程序的功能非常重要,当一个对象接收到一个消息后,调度程序会在接收对象的类中查找与该消息对应的方法,如果没有找到调度程序就进入超类中查找,如还是没有则根据继承规则继续向上游查找,如果到类继承关系的最顶层(NSObject类)还没有找到该消息的方法时就报运行时错误(编译时会报警告)。
    4)self 与 super
         a) self 是一个隐含的指针,指向接收消息的对象的指针。消息所调用的方法使用该指针参数查找它们要使用的实例          变量。
         b)super来之哪里呢?它不是参数也不是实例变量,而是由Objective-C编译器提供的某种神奇的功能。向super发消息时,实际上是在请求Objective-C向该类的超类发送消息。如果超类中没有定义的消息,Objective-C将按照继承的通常规则在继承链中查找。
    5)每个类都是NSObject的子类,而NSObject中定义了isa实例变量,所以每个类的对象(实例)第一实例变量就是isa,不过它是隐藏的。
     
    今天接着讲OPP技术中的另外一门技术--复合:
    在Objective-C中复合是如何实现的?它是通过在类中声明一个指向另一个类对象的指针作为实例变量,从而将这两个类进行复合。
    1)使用new 创建对象的时候,实际发生了两个步骤;第一个步骤,为对象分配内存,也就是说对象获得存储其实例变量的内存块;第二步,就是自动调用init方法,初始化对象使其处于可用状态。没有被初始化的指针都使nil.
     
     
     头文件内容如下:

    #import <Foundation/Foundation.h>

     

    @interface Engine:NSObject

    @end//Engine

     

    @interface Tire:NSObject

    @end// Tire

     

    @interface Car:NSObject

    {

    Engine *carEngine;

    Tire *carTire[4];

    }

    -(void)print;

    @end//Car

        
    源文件内容如下:

    #import "carPart.h"

     

    @implementation Engine

    -(NSString *)description

    {

    return(@"I am a Engine!");

    }

    @end//Engine

     

    @implementation Tire

    -(NSString *)description

    {

    return(@"I am a Tire!");

    }

    @end//Tire

     

    @implementation Car 

    //注意init方法的返回值类型是id,即是一个指向对象的指针,该函数在用new创建对象时自动被调用

    -(id) init

    {

    //需要先调用超类的init函数,并将结果赋给selfinit调用会依据继承关系一直回调用到类关系的顶层。

    if(self = [superinit])

    {

    carEngine = [Engine new];

     

    carTire[0] = [Tire new];

    carTire[1] = [Tire new];

    carTire[2] = [Tire new];

    carTire[3] = [Tire new];

    }

     

    //别忘了返回初始化后的对象指针

    returnself;

     

    }

     

    -(void)print

    {

    //注意双引号字符串前必须加@符号

    NSLog(@"%@",[carEnginedescription]);

    NSLog(@"%@",[carTire[0] description]);

    NSLog(@"%@",[carTire[1] description]);

    NSLog(@"%@",[carTire[2] description]);

    NSLog(@"%@",[carTire[3] description]);

    }

    @end//Car

     

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

    {

    Car * carPart = [Car new];

    [carPart print];

    }


     

    2)我们看到上面的程序发现,该结构比较死,如果我们能随时可以更换发动机和轮胎那么我们程序的机构就更灵活了。也许你发现了,这样修改是否像 策略模式 呢!


    在这里使用存取方法来实现上述想法。

    a)存取方法:用来读出或改变对象特定属性的方法。

    存取方法分为setter 和 getter方法,一般setter方法前都是用"set"作为前缀;getter方法前不能有 "get"前缀。setter方法的命名基础是“set” + “属性名”;而 getter方法命名的基础就是“属性名”。

    b)在cocoa中有“get”前缀的方法是有特殊意义的,如果“get”前缀出现在cocoa方法名称中,这就意味着该函数的返回值是通过该函数的参数返回的。

    c)setter方法和getter方法一般上成对出现的,当然可以不成对出现,如对于只读特性只有getter方法,对于密码特性只有setter方法。

    d)在Objective-C中所有对象之间的交互都是通过指针实现的。

    修改后的程序如下:

     头文件内容如下:

     

    /*

     *  Composition2.h

     *  Composition2

     *

     *  Created by yan li on 8/26/09.

     *  Copyright 2009 cat. All rights reserved.

     *

     */

     

    #import <Foundation/Foundation.h>

     

    @interface Engine:NSObject

    @end//Engine

     

    @interface Tire:NSObject

    @end// Tire

     

    @interface Car:NSObject

    {

    Engine *carEngine;

    Tire *carTire[4];

    }

    -(Engine *)carEngine;

    -(void)setCarEngine:(Engine*)engine;

     

    -(Tire*)carTireAtIndex:(int)index;

    -(void)setCarTire:(Tire*)tire 

          AtIndex:(int)index;

     

    -(void)print;

    @end//Car


    源文件内容如下:

     

    //#import <Foundation/Foundation.h>

    #import "Composition2.h"

     

    @implementation Engine

    -(NSString *)description

    {

    return(@"I am a Engine!");

    }

    @end//Engine

     

    @implementation Tire

    -(NSString *)description

    {

    return(@"I am a Tire!");

    }

    @end//Tire

     

    @implementation Car 

    /*//注意init方法的返回值类型是id,即是一个指向对象的指针,该函数在用new创建对象时自动被调用

    -(id) init

    {

    //需要先调用超类的init函数,并将结果赋给selfinit调用会依据继承关系一直回调用到类关系的顶层。

    if(self = [super init])

    {

    carEngine = [Engine new];

     

    carTire[0] = [Tire new];

    carTire[1] = [Tire new];

    carTire[2] = [Tire new];

    carTire[3] = [Tire new];

    }

     

    //别忘了返回初始化后的对象指针

    return self;

     

    }*/

    -(Engine*)carEngine

    {

    return carEngine;

    }

     

    -(void)setCarEngine:(Engine*)engine

    {

    carEngine = engine;

    }

     

    -(Tire*)carTireAtIndex:(int)index

    {

    if(index > 3 || index < 0)

    {

    NSLog(@"index error");

    exit(1);

    }

    return (carTire[index]);

    }

     

    //注意下面这个函数的名称的写法,比较独特以后会详细介绍

    -(void)setCarTire:(Tire*)tire AtIndex:(int)index

    {

    //一下if 语句是防御性编程

    if(index > 3 || index < 0)

    {

    NSLog(@"index error");

    exit(1);

    }

    carTire[index] = tire;

    }

    -(void)print

    {

    //注意双引号字符串前必须加@符号

    NSLog(@"%@",[carEngine description]);

    NSLog(@"%@",[carTire[0] description]);

    NSLog(@"%@",[carTire[1] description]);

    NSLog(@"%@",[carTire[2] description]);

    NSLog(@"%@",[carTire[3] description]);

     

    }

    @end//Car

     

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

    {

    Car * carPart = [Car new];

     

    // Car对象的调用代码中,使用对象属性setter方法随时修改对象的属性。

    Engine *engine = [Engine new];

    [carPart setCarEngine:engine];

     

    int i;

    //循环控制数要确认好

    for(i = 0; i< 4; i++)

    {

    Tire *tire = [Tire new];

    [carPart setCarTire:tire AtIndex:i];

    }

     

    [carPart print];

     

    return0;

    }

     

    3)该程序我们还可以改进,我们不但可以随时为我们的汽车安装发动机和轮胎,而且我们使用“继承”技术我们可以不断的扩展新的发动机和轮胎,这样我们还可以为我们的汽车安装新品排的发动机和轮胎,挖塞!听其来好像是使用了策略模式编程思想喔

  • 相关阅读:
    了解java注解
    使用java泛型设计通用方法
    dbutils基本使用
    jquery+ajax+struts2
    c3p0连接数据库的3种方式
    ASP单步调试工具
    设置网页图片不能被用户下载或者另存为
    简单树形菜单
    GBK,GB3212 Unicode编码问题详解
    html页面乱码问题解决方法编码批量转换
  • 原文地址:https://www.cnblogs.com/zhwl/p/2283076.html
Copyright © 2011-2022 走看看