——- android培训、IOS培训、期待与您交流! ———-
继承是在两个类之间之间建立关系的一种方式,它可以避免许多重复的代码。组合可以联合多个对象,让它们分工合作。在实际程序中,会同时用到继承和组合。
什么是组合
在Objective-C中,组合是通过包含作为实例变量的对象指针实现的。 以一个Pedal对象和一个Tire对象组合出一个虚构的Unicycle为例。Unicycle应该拥有一个指向Pedal对象的指针和一个指向Tire对象的指针。
@interface Unicycle : NSObject
{
Pedal *pedal;
Tire *tire;
}
@end // Unicycle
Pedal
和Tire
通过组合的方式构成了Unicycle
。
Car程序
假设一辆汽车只需要1台发电机和4个轮胎。以此搭建一个简单的汽车模型。
首先定义Tire
类:
#import <Foundation/Foundation.h>
@interface Tire : NSObject
@end // Tire
@implementation Tire
// 如果类中没有包含任何实例变量,可以省略接口定义中的花括号
- (NSString *) description
{
return (@"I am a tire. I last a while.");
} // description
@end // Tire
// Engine类
@interface Engine : NSObject
@end // Engine
@implementation Engine
- (NSString *) description
{
return(@"I am an engine.");
} // description
@end Engine
// Car类
@interface Car : NSObject
{
engine *engine;
Tire *tire[4];
}
- (void) print;
@end //Car
@implementation Car
- (id) init
{
// 调用[super init]让超类完成初始化工作,init方法返回的值(id类型的数据,泛型对象指针)就是被初始化的对象。
// 将[super init]返回的值赋给self是为了防止超类在初始化过程中返回的对象与一开始创建的不一致。
if (self = [super init])
{
engine = [Engine new];
tires[0] = [Tire new];
tires[1] = [Tire new];
tires[2] = [Tire new];
tires[3] = [Tire new];
}
return (self);
} // init
- (void) print
{
NSLog(@"%@", engine);
NSLog(@"%@", tires[0]);
NSLog(@"%@", tires[1]);
NSLog(@"%@", tires[2]);
NSLog(@"%@", tires[3]);
} // print
@end // Car
每个Car对象都会为指向engine和tires的指针分配内存,但是真正包含在Car中的并不是engine和tires变量,只是内存中的其他对象的引用指针。为新建的Car对象分配内存时,这些指针将被初始化为nil
。
print
方法通过NSLog()
输出实例变量。%@
调用每个对象的description
方法并显示结果。
// main函数创建新对象*Car*,并告诉它输出自身信息,然后推出程序。
int main(int argc,const char *argv[])
{
Car *car;
car = [Car new];
[car print];
return 0;
} // main
属性的存取方法
存取方法用来读取或改变某个对象的属性。 给变量赋值的称为setter方法,访问对象属性的称为getter方法。
下面为Car类添加setter和getter方法。
首先设置接口:
@interface Car : NSObject
{
Engine *engine;
Tire *tires[4];
}
- (Engine *) engine; // 访问engine的属性
- (void) setEngine : (Engine *) newEngine; // 设置engine的属性
- (Tire *) tireAtindex : (int) index; // 访问tire的属性
- (void) setTire : (Tire *) tire atIndex : (int) index; // s设置tire的属性
- (void) print;
@end // Car
Cocoa对存取方法的命名惯例
setter方法根据它所更改的属性的名称来命名,并加上前缀set
getter方法则是以其返回的属性的名称来命名。不要将get作为getter方法的前缀。
get这个词在Cocoa中有特殊含义。如果get出现在Cocoa的方法名称中,暗示这个方法会将你传递的参数作为指针来返回数值。
// engine方法的实现
@implementation Car
// getter方法engine返回实例变量engine的当前值。
// 在Objective-C中所有对象间的交互都是通过指针实现的,所以方法engine返回的是一个指针,指向Car中的engine对象。
- (Engine *) engine
{
return (engine);
} // engine
// setter方法setEngine : 将实例变量engine的值赋为参数所指向的值,实际被复制的不是engine变量,而是指向engine的指针值。
- (void) setEngine : (Engine *) newEngine
{
engine = newEngine;
} // setEngine
// tires属性的存取方法
- (void)setTire : (Tire *) tire atIndex : (int) index
{
if (index < 0 || index > 3)
{
NSLog(@"bad index (%d) in setTire : atIndex :" , index);
exit(1);
}
tires[index] = tire;
} // setTire : atIndex :
- (Tire *) tireAtIndex : (int) index
{
if (index < 0 || index > 3)
{
NSLog (@"bad index (%d) in "tireAtIndex:" , index");
exit (1);
}
return (tires[index]);
} // tireAtIndex:
@end // Car
更新main
函数如下,采用存取方法初始化car
对象:
int main (int argc,const char *argv[])
{
Car *car = [Car new];
Engine *engine = [Engine new];
[car setEngine : engine];
for (int i = 0 ; i < 4 ; i++)
{
Tire *tire = [Tire new];
[car setTire : tire atIndex : i];
}
[car print];
return (0);
} // main
利用存取方法扩展程序
// 创建新engine子类slant6
@interface Slant6 : Engine
@end // Slant6
@implementation Slant6
- (NSString *) description
{
return (@"I am a slamt-6.OOOOM!!!!");
} // description
@end // Slant6
// 创建新Tire子类AllWeatherRadial
@interface AllWeatherRadial : Tire
@end // AllWeatherRadial
@implementation AllWeatherRadial
- (NSString *) description
{
return (@"I am a tire for rain or shine.");
} // description
@end // AllWeatherRadial
调整一下main
函数,使用engine和tire的子类:
int main (int argc, const char *argv[])
{
Car *car = [Car new];
for (int i = 0; i < 4; i++)
{
Tire *tire = [AllWeatherRadial new];
[car setTire : tire atIndex : i];
}
Engine *engine = [Slant6 new];
[car setEngine : engine];
[car print];
return (0);
} // main