间接(indirection)
"只要再多添加一层间接,计算机科学中就没有解决不了的问题。"
- 例子
- 电话薄
- 让他人代替你自己去完成工作
- 编写一段代码来查询其他代码,并通过它继续访问另一层代码。
- 推诿
- 变量与间接
- 使用文件名的间接
在面向对象编程中使用间接
使用间接来调用代码,不是直接调用某个函数,而是间接调用。
- 过程式编程(Procedual Programming)
#import <Foundation/Foundation.h>
typedef enum {
kCircle,
kRectangle,
kEgg,
} ShapeType;
typedef enum {
kRedColor,
kGreenColor,
kBlueColor
} ShapeColor;
//不同图形元素
typedef struct {
int x, y, width, height;
} ShapeRect;
//图形结构
typedef struct {
ShapeType type;
ShapeColor fillColor;
ShapeRect bounds;
} Shape;
//颜色函数
NSString *colorName(ShapeColor fillColor)
{
switch (fillColor) {
case kRedColor:
return @"red";
break;
case kGreenColor:
return @"green";
break;
case kBlueColor:
return @"blue";
break;
}
return @"no clue";
}
//绘制图形
void drawCircle(ShapeRect bounds, ShapeColor fillColor)
{
NSLog(@"drawing a Circle at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}
void drawRectangle(ShapeRect bounds, ShapeColor fillColor)
{
NSLog(@"drawing a Rectangle at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}
void drawEgg(ShapeRect bounds, ShapeColor fillColor)
{
NSLog(@"drawing a Egg at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}
void drawShapes(Shape shapes[], int count)
{
for (int i=0; i<count; i++) {
switch (shapes[i].type) {
case kCircle:
drawCircle(shapes[i].bounds, shapes[i].fillColor);
break;
case kRectangle:
drawRectangle(shapes[i].bounds, shapes[i].fillColor);
break;
case kEgg:
drawEgg(shapes[i].bounds, shapes[i].fillColor);
break;
default:
break;
}
}
}
int main(int argc, const char * argv[]) {
Shape shapes[3];
ShapeRect rect0 = {0, 0, 10, 30};
shapes[0].type = kCircle;
shapes[0].fillColor = kRedColor;
shapes[0].bounds = rect0;
ShapeRect rect1 = {30, 40, 50, 60};
shapes[1].type = kRectangle;
shapes[1].fillColor = kGreenColor;
shapes[1].bounds = rect1;
ShapeRect rect2 = {15, 18, 37, 29};
shapes[2].type = kEgg;
shapes[2].fillColor = kBlueColor;
shapes[2].bounds = rect2;
drawShapes(shapes, 3);
return 0;
}
修改过去正常工作的代码很可能会引入新的错误。
建立在函数之上,数据为函数服务。
代码例子 3.2.1 Shapes-Procedural
- 面向对象编程
- 以数据为中心,函数为数据服务
- 代码例子
3.2.2 Shapes-Object
-
id
是一种泛型,可以用来引用任何类型的对象(id实际上是一个指向结构体的指针)。 - 方括号在OC中其他意义:用于通知某个对象该去做什么。
[shape draw];
表示通知shape对象执行draw操作 - 发送消息(调用方法):通知对象执行某种操作。
- 类是一种能够实例化成对象的结构体。
- 如果在运行时改变某个类,则该类的所有对象自动继承这些变化。
#import <Foundation/Foundation.h>
typedef enum {
kRedColor,
kGreenColor,
kBlueColor
} ShapeColor;
//不同图形元素
typedef struct {
int x, y, width, height;
} ShapeRect;
//颜色函数
NSString *colorName(ShapeColor fillColor)
{
switch (fillColor) {
case kRedColor:
return @"red";
break;
case kGreenColor:
return @"green";
break;
case kBlueColor:
return @"blue";
break;
}
return @"no clue";
}
@interface Circle : NSObject
{
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end //Circle
@implementation Circle
- (void) setFillColor:(ShapeColor) c
{
fillColor = c;
}
- (void) setBounds:(ShapeRect) b
{
bounds = b;
}
- (void) draw
{
NSLog(@"drawing a Circle at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}
@end
@interface Rectangle : NSObject
{
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end //Rectangle
@implementation Rectangle
- (void) setFillColor:(ShapeColor) c
{
fillColor = c;
}
- (void) setBounds:(ShapeRect) b
{
bounds = b;
}
- (void) draw
{
NSLog(@"drawing a Rectangle at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}
@end
@interface Egg : NSObject
{
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end //Egg
@implementation Egg
- (void) setFillColor:(ShapeColor) c
{
fillColor = c;
}
- (void) setBounds:(ShapeRect) b
{
bounds = b;
}
- (void) draw
{
NSLog(@"drawing a Egg at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}
@end
// 补充一个三角形
@interface Triangle : NSObject
{
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end //Triangle
@implementation Triangle
- (void) setFillColor:(ShapeColor) c
{
fillColor = c;
}
- (void) setBounds:(ShapeRect) b
{
bounds = b;
}
- (void) draw
{
NSLog(@"drawing a Triangle at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}
@end
void drawShapes(id shapes[], int count)
{
for (int i=0; i<count; i++) {
id shape = shapes[i];
[shape draw];
}
}
int main(int argc, const char * argv[]) {
id shapes[4];
ShapeRect rect0 = {0, 0, 10, 30};
shapes[0] = [Circle new];
[shapes[0] setBounds:rect0];
[shapes[0] setFillColor:kRedColor];
ShapeRect rect1 = {30, 40, 50, 60};
shapes[1] = [Rectangle new];
[shapes[1] setBounds:rect1];
[shapes[1] setFillColor:kGreenColor];
ShapeRect rect2 = {15, 18, 37, 29};
shapes[2] = [Egg new];
[shapes[2] setBounds:rect2];
[shapes[2] setFillColor:kBlueColor];
ShapeRect rect3 = {3, 4, 5, 0};
shapes[3] = [Triangle new];
[shapes[3] setBounds:rect3];
[shapes[3] setFillColor:kBlueColor];
drawShapes(shapes, 4);
return 0;
}
有关术语
- class
- object
- instance
- message
- method
- method dispatcher
- interface
- implementation
OC中的OOP
@interface Circle : NSObject
{
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void) setFillColor: (ShapeColor) fillColor;
- (void) setBounds: (ShapeRect) bounds;
- (void) draw;
@end //Circle
@implementation Circle
- (void) setFillColor:(ShapeColor) c
{
fillColor = c;
}
- (void) setBounds:(ShapeRect) b
{
bounds = b;
}
- (void) draw
{
NSLog(@"drawing a Circle at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}
@end
-
@interface
OC编译器需要一些有关类的信息-
@
可以看成是对C语言的扩展 -
instance variable(实例变量) :
@interface
下的花括号的内容:
{ @private ShapeColor fillColor; ShapeRect bounds; }
-
method declaration(方法声明)。有点像C语言中的函数原型。
-
表示对象方法,+
表示类方法。(void)
表示返回类型。
- (void) setFillColor: (ShapeColor) fillColor; - (void) setBounds: (ShapeRect) bounds; - (void) draw;
-
infix notation(中缀符) : 方法的名称及其参数都是合在一起的
[circle setFillColor: kRedColor]
表示调用带一个参数的方法 - 如果方法使用参数,则需要冒号,否则不需要冒号
- 提倡@end语言后添加注释来注明类的名称
-
-
@implementation
- @implementation中可以定义在@interface中声明过和没有声明过的方法
- OC中不存在真正的私有方法
-
实例化对象
- instantiation(实例化)
-
[Circle new]
发送new消息
软件实体应该对扩展开放,而对修改关闭。 ---- 开放/关闭原则(Bertrand Meyer)