1.什么是复合
严格来说,只有对象间的组合才是复合
Car程序
//Car程序
//一辆车需要一台发动机(Engine),四个轮胎(Tire)
#import <Foundation/Foundation.h>
//Tire类
@interface Tire : NSObject
@end
@implementation Tire
- (NSString *) description{
return (@"I am a tire");
}
@end//Tire
//Engine类
@interface Engine : NSObject
@end
@implementation Engine
- (NSString *) description{
return (@"I am a engine");
}
@end//Engine
//Car类
@interface Car : NSObject{
Engine *engine;
Tire *tires[4];
}
-(void)print;
@end
@implementation Car
//初始化实例变量的init方法
-(id)init{
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;
}
//通过NSLog()输出实例变量,记住%@只是调用每个对象的description
-(void)print{
NSLog(@"%@",engine);
NSLog(@"%@",tires[0]);
NSLog(@"%@",tires[1]);
NSLog(@"%@",tires[2]);
NSLog(@"%@",tires[3]);
}
@end//Car
int main(int argc, const char * argv[]) {
Car *car;
car = [Car new];
[car print];
return 0;
}
//运行结果
2018-10-05 09:47:48.031284-0700 Car[598:13721] I am a engine
2018-10-05 09:47:48.031592-0700 Car[598:13721] I am a tire
2018-10-05 09:47:48.031634-0700 Car[598:13721] I am a tire
2018-10-05 09:47:48.031651-0700 Car[598:13721] I am a tire
2018-10-05 09:47:48.031666-0700 Car[598:13721] I am a tire
Program ended with exit code: 0
如果类中没有包含任何实例变量,便可以省略掉接口定义中的花括号
Tire类中惟一的方法是description,并没有在接口中声明,我们又怎么可以在Tire类中调用description方法呢,这时就要靠Cocoa
为了让父类(NSObject)将所有需要的初始化工作一次性完成,需要调用[super init],init方法返回的值(id,泛指对象数据)就是被初始化的对象,目的是为了防止父类在初始化过程中返回的对象与一开始创建的不一致,后面会继续讲述init方法
//初始化实例变量的init方法
-(id)init{
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;
}
2.自定义NSLog()
NSLog()可以使用%@格式说明符来输出对象,NSLog()处理%@说明符时,会询问参数列表中相应的对象以得到这个对象的描述,从技术上说,也就是NSLog()给这个对象发送了description消息,然后对象的description方法生成一个NSString并将返回,NSLog()就会在输出结果中包含这个字符串
因此,在类中提供description方法就可以自定义NSLog()会如何输出对象
3.存取方法
存取方法是用来读取或改变某个对象属性的方法
- setter方法:为对象中的变量赋值,setter方法根据它所改的属性的名称来命名,并加上前缀set
-
getter方法:提供了通过对象自身访问对象属性的方式,getter方法则是以其返回的属性名称命名,不要加前缀,OC中get有特殊含义
通常情况下,两者同时编写
3.1设置engine属性的存取方法
//声明
-(Engine *)engine;//get方法返回实例变量engine的当前值
- (void)setEngine:(Engine *)newEngine;
//实现
-(Engine *)engine{
return engine;
}
- (void)setEngine:(Engine *)newEngine{
engine = newEngine;
}
3.2设置tires属性的存取方法
//声明
- (void) setTire: (Tire *)tire atIndex: (int)index;
- (Tire *) tireAtIndex: (int)index;
//实现
- (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;
}
- (Tire *) tireAtIndex: (int)index{
if(index < 0 || index > 3) {
NSLog(@"bad index (%d) in setTire:atIndex:",index);
exit(1);
}
return (tires[index]);
}
3.3扩展Car程序
用新的轮胎和引擎代替
//Car程序扩展
#import <Foundation/Foundation.h>
//Tire类
@interface Tire : NSObject
@end
@implementation Tire
- (NSString *) description{
return (@"I am a tire");
}
@end
//Tire类子类
@interface AllWeatherRadial : Tire
@end
@implementation AllWeatherRadial
- (NSString *) description{
return (@"I am a tire for rain or shine");
}
@end
//Engine类
@interface Engine : NSObject
@end
@implementation Engine
- (NSString *) description{
return (@"I am a engine");
}
@end
//Engine类子类
@interface Slant6 : Engine
@end
@implementation Slant6
- (NSString *) description{
return (@"I am a Slant-6");
}
@end
//Car类
@interface Car : NSObject{
Engine *engine;
Tire *tires[4];
}
- (Engine *)engine;
- (void)setEngine:(Engine *)newEngine;
- (void) setTire: (Tire *)tire atIndex: (int)index;
- (Tire *) tireAtIndex: (int)index;
-(void)print;
@end
@implementation Car
//初始化实例变量的init方法
-(id)init{
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;
}
//engine存取
-(Engine *)engine{
return engine;
}
- (void)setEngine:(Engine *)newEngine{
engine = newEngine;
}
//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;
}
- (Tire *) tireAtIndex: (int)index{
if(index < 0 || index > 3) {
NSLog(@"bad index (%d) in setTire:atIndex:",index);
exit(1);
}
return (tires[index]);
}
//通过NSLog()输出实例变量,记住%@只是调用每个对象的description
-(void)print{
NSLog(@"%@",engine);
NSLog(@"%@",tires[0]);
NSLog(@"%@",tires[1]);
NSLog(@"%@",tires[2]);
NSLog(@"%@",tires[3]);
}
@end
//主函数
int main(int argc, const char * argv[]) {
Car *car;
car = [Car new];
Engine *engine = [Slant6 new];
[car setEngine:engine];
for (int i = 0; i < 4; i++) {
Tire *tire = [AllWeatherRadial new];
[car setTire:tire atIndex:i];
}
[car print];
return 0;
}
//运行结果
018-10-05 18:51:07.995514-0700 Car[588:13341] I am a Slant-6
2018-10-05 18:51:07.995811-0700 Car[588:13341] I am a tire for rain or shine
2018-10-05 18:51:07.995843-0700 Car[588:13341] I am a tire for rain or shine
2018-10-05 18:51:07.995889-0700 Car[588:13341] I am a tire for rain or shine
2018-10-05 18:51:07.995911-0700 Car[588:13341] I am a tire for rain or shine
Program ended with exit code: 0
3.4复合还是继承
- 继承的类之间建立的关系为“is a”(是一个),如三角形是一个形状。因此,如果可以说“X是一个Y,那就可以使用继承”
- 复合的类之间建立的关系为“has a”(有一个),如汽车有一个引擎四个轮胎。因此,如果可以说“X有一个Y,那就可以使用复合