今天我们要讲的复合,当然不是小情侣吵着分手,然后又在一起的复合。
复合遵循一个合成复用原则,又称为组合或者聚合复用原则。该原则的内容是:尽量使用对象组合,而不是继承来达到复用的目的。用聚合可以使系统更加灵活,类与类之间的耦合度降低。在objective-c中,复合是指将多个组件组合在一起,配合使用,从而得到一个完整的作品。严格的说,只有对象之间的组合才是复合。类中的基本数据和结构型对象不算复合。
继承和复合,是类与类之间两种重要的关系。接下来,我们就借用书本上的例子来介绍下复合关系。
假如我们要构建一个简单的汽车模型,那么要有一个发动机(Engine)和四个轮子(Tire)。基本定义的代码如下:
首先,先定义和简单的实现Tire类。
1 @interface Tire : NSObject 2 @end //Tire 3 4 @implementation Tire 5 -(NSString *) description{ 6 return (@"I am a tire. I last a while."); 7 } 8 @end
在实现方法中的description没有定义,那么他是哪里来的呢?在Cocoa中,NSLog()可以使用%@格式说明符来输出对象,NSLog()将对象发送了description消息,然后对象的description方法生成一个NSString并将其返回。所以,在类中提供description方法,就可以自定义NSLog()。
然后定义和简单的实现Engine类。
1 @interface Engine : NSObject 2 @end 3 4 @implementation Engine 5 -(NSString *) description { 6 return (@"I am an engine. Vroom!"); 7 } 8 @end
然后定义汽车(Car)类本身。
1 @interface Car : NSObject 2 { 3 Engine *engine; 4 Tire *tires[4]; //四个轮子,定义一个四个数的数组。 5 } 6 -(void) drive; 7 @end // Car 8 9 @implementation Car 10 -(id) init 11 { 12 if(self = [super init]) 13 { 14 engine = [Engine new]; 15 tires[0] = [Tire new]; 16 tires[1] = [Tire new]; 17 tires[2] = [Tire new]; 18 tires[3] = [Tire new]; 19 } 20 return (self); 21 } 22 23 -(void) drive{ 24 NSLog(@"%@",engine); 25 NSLog(@"%@",tires[0]); 26 NSLog(@"%@",tires[1]); 27 NSLog(@"%@",tires[2]); 28 NSLog(@"%@",tires[3]); 29 } 30 @end
在实现Car类的代码中,我们定义了一个类型为id的init的方法。这里的作用是:初始化实例变量,创建1个engine变量和4个tire变量。使用new创建新对象的时候,系统会自动给对象分配内存,然后自动调用init方法,使该对象进入可以使用的状态。
关于init方法中,if语句:if(self = [super init]),这个条件是什么意思呢?为了让超类(在这里是指:NSObject)将所有需要的初始化工作一次性完成。需要调用[super init]。init方法的返回值(id类型数据,即泛型对象指针)就是被初始化的对象。而将返回的结果赋值给self则是Objective-c的惯例。这样做是为了防止超类在初始化过程中返回的对象与一开始创建的不一致。
最后在main主函数中,创建一个Car对象,然后调用drive方法,代码如下:
1 int main(int argc, const char * argv[]) 2 { 3 Car *car; 4 car = [Car new]; 5 [car drive]; 6 return 0; 7 }
运行效果: