@implementation Circle - (void) draw { NSLog (@"drawing a circle at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor)); } // draw @end // Circle
@implementation Rectangle - (void) draw { NSLog (@"drawing a rect at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor)); } // draw @end // Circle
重载
Objective-C 提供某种方式来重载方法,并且仍然调用超类的实现方式。当需要超类实现自身的功能,同时在前面或后面执行某些额外的工作时,这种机制非常有用。为了调用继承方法的实现,需要使用 super 作为方法调用的目标。
示例
例如,如果要改写绘图软件,将所有原本是红色的圆统一绘制成绿色。因为 setFillColor: 是在 Shape 类中定义的。因此,只要在 Circle 类中重载 setFillColor: 方法就可以解决该问题。我们考虑颜色参数,如果它是红色,就把它改成绿色。然后,使用 super 通知超类(shape)将更改的颜色存储到 fillColor 实例变量中。
1 2 3 4 5 6 7 8 9 10
@impletement Circle - (void) setFillColor : (ShapeColor) c { if (c == kRedColor) { c = kGreenColor; } [super setFillColor: c]; } // setFillColor // Circle 类其他实现部分保持不变 @end // Cicle
Tips: 重载方法时,调用超类方法总是一个不错的选择,这样可以确保能够获得方法实现的所有特性。
复合
在 Objective-C 中,复合是通过包含作为实例变量的对象指针实现的。
例如,一辆轿车由一个发动机(Engine)和四个轮子(Tire)组成,下面我们用程序描述它。
示例
Tire 类
Tire 类只有一个 description 方法:
1 2 3 4 5 6 7 8 9 10
@interface Tire : NSObject @end // Tire
@implementation Tire
- (NSString *) description { return (@"I am a tire. I last a while"); } @end // Tire
Engine 类
与 Tire 类类似,Engine 类也只有一个 descrption 方法:
1 2 3 4 5 6 7 8 9 10
@interface Engine : NSObject @end // Engine
@implementation Engine
- (NSString *) description { return (@"I am an Engine. Vroom!"); } @end // Engine
Car 类
声明:
Car 类本身拥有一个 engine 对象和一个由 4 个 tires 对象组成的 C 数组。它通过复合的方式来组装自己。 Car 同时还有一个 print 方法,该方法使用 NSLog 输出轮胎和发动机的描述:
1 2 3 4 5 6 7 8 9
@interface Car : NSObject { Engine *engine; Tire *tires[4]; }
- (void) print;
@end // Car
每一个 Car 对象都会为指向 engine 和 tires 的指针分配内存。但是真正包含在 Car 中的并不是 engine 和 tires 变量,而只是内存中存在的其他对象的引用。为新建的 Car 分配内存时,这些指针将被初始化为 nil (零值),也就是说这辆汽车现在还没有发动机也没有轮胎。你可以将他想象成还在流水线上组装的汽车框架。
实现:
下面让我们看看 Car 类的实现。首先是一个初始化实例变量的 init 方法。init 方法创建一个 engine 变量和 4 个 tires 变量,用以装配汽车。使用 new 创建新对象时,实际上系统要完成两个步骤: