复合 composition
object-c中,复合是通过包含作为实例变量的对象指针实现的。严格的说,只有对象间的组合叫复合。
以汽车模型为例,1辆汽车(Car)需要1台发动机(Engine)和4个轮胎(Tire),这里不去研究真正的轮胎和发动机的物理模型,而仅包含方法的类来输出各自代表的含义:轮胎的对象说它们是轮胎,发动机的对象说它们是发动机。
1 @interface Car : NSObject 2 { 3 Engine *engine; 4 Tyre *tire; 5 } 6 @end //Car
以上代码可以看出,engine和tire是通过复合的方式组成Car。
1 @interface Engine : NSObject 2 @end //Engine 3 4 @implementation Engine 5 -(NSString)Descroption 6 { 7 return (@"I am engine. Vroom"); 8 } //description 9 @end //Engine
Engine类只有一个description方法
1 @interface Car : NSObject 2 { 3 Engine *engine; 4 Tire *tires[4]; 5 } 6 -(void)print; 7 @end//Car
Car 拥有engine对象和一个由4个tire对象组成的数组,通过复合的方式组装自己,Car同时还有一个print方法,该方法使用NSLog()来输出轮胎和发动机的描述。
因为engine和tires是Car的实例变量,所以它们是复合的。
下面我们来看看Car的实现:
1 @implementation Car 2 -(id)init 3 { 4 if(self = [super init]){ 5 engine = [engine new]; 6 tires[0] = [Tire new]; 7 tires[1] = [Tire new]; 8 tires[2] = [Tire new]; 9 tires[3] = [Tire new]; 10 } 11 return(self); 12 }//init
1 -(void)print 2 { 3 NSLog(@"%@",engine); 4 NSLog(@"%@",tires[0]); 5 NSLog(@"%@",tires[1]); 6 NSLog(@"%@",tires[2]); 7 NSLog(@"%@",tires[3]); 8 }//print 9 @end//Car
print是通过NSlog
1 int main (int argc,const char *argv[]) 2 { 3 Car *car; 4 car = [Car new]; 5 [car print]; 6 return(0); 7 }//main
运行程序后输出:
1 @interface Car : NSObject 2 { 3 Engine *engine; 4 Tire *tire[4]; 5 } 6 -(Engine *)engine; 7 -(void) setEngine: (Engine *)newEngine; 8 -(Tire *)tireAtIndex : (int)index; 9 -(void)setTire:(Tire *)tire atIndex:(int)index; 10 -(void)print; 11 @end//Car
代码中的实例变量并没有变化,但是新增了2对方法,engine和setEngine:用来处理发动机的属性;tireAtIndex:和set:atIndex:用来处理轮胎的属性。
存储方法总是成对出现的,一是用来设置属性的值,一是用来读取属性的值。有时只有一个getter方法(用于只读,例如磁盘文件大小),或者有时只有一个setter方法(例如设置密码)也是合理的。
1 -(Engine *)engine; 2 -(void)setEngine : (Engine)newEngine;
第一对存取方法用来访问发动机的属性,在代码中调用Car对象的engine方法可以访问engine方法,调用setEngine方法可以更改发动机的属性。下面是2个方法的实现:
1 -(Engine *)engine 2 { 3 return (engine); 4 }//engine:返回实例变量engine的当前值,engine返回的是指针,指向Car中的发动机对象 5 6 -(void)setEngine:(Engine *)newEngine 7 { 8 engine = newEngine; 9 }//setEngine:将实例变量engine的赋值为参数所指向的
在代码中实际运用这些存取方法,可编写如下代码:
1 Engine *engine = [Engine new]; 2 3 [car setEngine : engine]; 4 5 NSLog(@"the car's engine is %@",[car engine]);
4、设置tires属性的存取方法
1 -(void)setTire:(Tire *)tire atIndex : (int)index; 2 -(Tire *)tireAtIndex:(int)index;
由于汽车的4个轮胎都有自己不同的位置,所以Car对象包含一个轮胎的数组。这里我们 需要用索引器而不能直接访问tires数组。为汽车配置轮胎时,不仅需要知道是哪个轮胎还需要知道每个轮胎在汽车上的具体位置。
实现代码如下:
1 -(void)srtTire:(Tire *)tire atIndex: (int)index; 2 { 3 if(index < 0 || index > 3){ 4 NSLog(@"bad index (%d) in setTire:atIndex : ",index); 5 exit(1); 6 } 7 tires[index] = tire; 8 }//setTire:atIndex: 9 10 -(Tire *)tireAtIndex : (int)index 11 { 12 if(index < 0 ||index>3) 13 { 14 NSLog(@"bad index (%d) in tireAtIndex : ",index); 15 exit(1); 16 } 17 return(tires[index]); 18 }//tireAtIndex:
在代码中实际运用这些存取方法,可编写如下代码:
1 Tire *tire =[Tire new]; 2 [car setTire : tire atIndex:2]; 3 NSLog(@"tire number two is %@",[car tireAtIndex: 2]);
因为Car类不再通过自身的方法进行部件装配,所以必须跟新main()函数来创建它们,具体调整如下:
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 serTire : tire atIndex : i]; } //car = [Car new]; [car print]; return(0); }//main
这里main()创建了一辆新车,然后为其创建并配置了一台新的发动机,接下来循环4次for,每次都创建一个轮胎并安装在汽车上,然后输出汽车的详细信息并退出程序。
@internet Slant6 : Engine @end @implementation Slant6 -(NSString *)description { return(@"I am a slant-6."); } //description @end //Slant6
Slant6是一种发动机,因为它们可以是Engine的子类;在car类中,setEngine:方法需要的是engine型的参数,所以我们可以传递Slant6型参数。
Slant6中,description方法被重写,用来输出信息。
1 @interface AllWeatherRadial : Tire 2 @end 3 4 @implementation AllWeatherRadial 5 -(NSStirng *)description 6 { 7 return(@"I am a tire for rain or shine."); 8 } //description 9 @end //AllWeatherRadial
最后调用main()函数,使用新型的发动机和轮胎:
1 int main (int argc,const char *argv[]) 2 { 3 Car *car=[Car new]; 4 //Engine *engine = [Engine new]; 5 // [car setEngine : engine]; 6 for(int i = 0 ; i < 4 ; i++) 7 { 8 //Tire *tire = [Tire new]; 9 [car serTire : tire atIndex : i]; 10 } 11 Engine *engine = [Slant6 new]; 12 [car setEngine : engine]; 13 //car = [Car new]; 14 [car print]; 15 return(0); 16 }//main
运行结果如下: