第五章、复合

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,那就可以使用复合
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,808评论 1 32
  • 综述 数组和结构体是聚合类型,其值由许多元素或成员字段的值组成,且都有固定内存大小的数据结构 数组是由同构的元素组...
    糖醋小排_0579阅读 625评论 0 0
  • 1.什么是复合?在Objective-C 中,复合是通过包含作为实例变量的对象指针实现的:(我们定义一辆车有一个发...
    poo_om阅读 379评论 0 0
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 3,243评论 2 9
  • 故障: 客户反应找车打开空调,空调不凉。 诊断: 1、由于客户不懂车,首先查看空调开关是否打开,查看空调开关已经打...
    宏宇_8a57阅读 712评论 0 1

友情链接更多精彩内容