编程中的复合就像音乐中的作曲一样:将多个组件组合在一起配合使用
从而得到完美的作品(程序中的复合其实就是类中包含类)
来了:在软件开发过程中,程序员可能会使用一个Pedal(脚踏板/脚蹬子)
对象和一个Tire(车轮)对象组合出虚拟的独轮车。
@interface Unicycle:NSObject
{
Pedal *pedal;
Tire *tire;
}
@end //Unicycle
Pedal和Tire通过复合的方式组成了Unicycle独轮车。
来个新的程序吧:
car程序
来看看如何搭建一个汽车模型:
包括一个发动机和4个轮胎
使用两个只包含一个方法的类来输出他们各自所代表的含义:
轮胎对象会说:我们是轮胎
发动机对象会说:我是发动机
当然在真正的程序中,轮胎会有气压和操控能力等属性。
发动机也会有马力和油耗等属性。
来看一下程序:
首先导入 Foundation框架的头文件
#import <Foundation/Foundation.h>
然后是我们的 Tire 类,类里面只有一个 descriotion 方法。
@interface Tire:NSObjet
@end // Tire
@implementation Tire
-(NSString *) description
{
return (@"I am a tire,I last a while");
}//description
@end //Tire
说明:如果类中不包含任何实例变量,就可以省去上面代码中的花括号。
其实,Tire类中只有一个方法:description 并且没有在接口中声明,
从哪里来的呢?
自定义NSLog
记住:通过NSLog()可以使用%@格式说明符来输出对象,NSLog()处理%@
说明符的时候,会询问参数列表中相应的对象,以得到这个对象的描述
从技术上,就是NSLog给这个对象发送描述消息,然后对象的description
生成一个NSString并返回。之后NSLog()在其输出中包含这个字符串。
一句话:
在类中添加description方法就可以自定义NSLog如何输出对象。
当然,在自定义的NSLog中,可以返回一个字面值 NSString 例如
@"I am a cheese Danish Object"(丹麦乳酪蛋糕,其实我不是很喜欢)
也可以构造一个描述该对象所有此信息的字符串,比如:这个蛋糕的
脂肪含量和卡路里。
在Cocoa中,NSArray类管理的是对象的集合,它的description方法
提供数组自身的信息,例如:数组中对象的个数和每一个对象所包含的
描述,当然,对象的描述是向数组中的对象发别发送description消息得
来的、
其实复合和继承的区别就是 继承是你是我 复合是你有我
让我们回到我们的car程序:
看看 Engine(发动机) 类,与Tire一样,Engine也包含了一个
description方法,在真实的程序中,Engine类会包含start(启动)
accelerate(加速)等方法和RPM(转数)等实例变量。
@interface Engine:NSObject
@end //Engine
@implementation Engine
-(NSString *) description
{
return (@"I am a engine,Vrooom!")
}
@end //Engine
程序的最后是Car(闪耀登场)
它拥有一个Engine对象和一个由4个tires对象组成的C数组,通过
复合的方式来组装自己。还有一个print方法,这个方法使用NSLog()
来输出轮胎和发动机的描述:
@interface Car:NSObject
{
Engine *engine;
Tire *tires[4];
}
-(void) print;
@end // car
每一个car对象都会为指向 engine和tires的指针分配内存
当然,真正包含在car里面的并不是Engine和Tire变量,而只是内存中
其他对象的引用。为新建的car分配内存的时候,这些指针将被初始化
为nil(零值)。
我们来瞧瞧car类的实现:
@implementation Car
-(id) init
{
if(self=[super init])
{
engine = [Engine new];
tires[0] = [Trie 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
注意:关于if语句:
有一个if语句看起来是相当的奇怪:
if(self=[super init])
如果父类(NSObject)可以完成所需要的一次性初始化
就调用[super init] init方法的返回值(id,泛型对象指针)
描述了被初始化的对象。
将[super init]结果赋值给self是Objective-C的标准惯例
防止超类在初始化的过程中返回的对象不同于原来创建的对象
(点头微笑吧)
最后一部分:main
int main(int argc,const char *argv[])
{
Car *car;
car = [Car new];
[car print];
return (0);
}//main
好 现在可以运行了