Objective-C中的继承与复合技术

Objective-C中的继承与复合技术

学习了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函数,并将结果赋给self;init调用会依据继承关系一直回调用到类关系的顶层。
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;


}


-(void)print
{
//注意 双引号字符串前 必须加@符号
NSLog(@"%@",[carEngine description]);
NSLog(@"%@",[carTire[0description]);
NSLog(@"%@",[carTire[1description]);
NSLog(@"%@",[carTire[2description]);
NSLog(@"%@",[carTire[3description]);

@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函数,并将结果赋给self;init调用会依据继承关系一直回调用到类关系的顶层。
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[0description]);
NSLog(@"%@",[carTire[1description]);
NSLog(@"%@",[carTire[2description]);
NSLog(@"%@",[carTire[3description]);


@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];

return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值