间接(indirection)

“只要再多添加一层间接,计算机科学中就没有解决不了的问题。”

  • 例子
    • 电话薄
    • 让他人代替你自己去完成工作
    • 编写一段代码来查询其他代码,并通过它继续访问另一层代码。
    • 推诿
  • 变量与间接
  • 使用文件名的间接

在面向对象编程中使用间接

使用间接来调用代码,不是直接调用某个函数,而是间接调用。

  • 过程式编程(Procedual Programming)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#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操作
    • 发送消息(调用方法):通知对象执行某种操作。
    • 类是一种能够实例化成对象的结构体。
    • 如果在运行时改变某个类,则该类的所有对象自动继承这些变化。
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@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
  1. @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语言后添加注释来注明类的名称
  1. @implementation
    • @implementation中可以定义在@interface中声明过和没有声明过的方法
    • OC中不存在真正的私有方法
  2. 实例化对象
    • instantiation(实例化)
    • [Circle new] 发送new消息
  3. 软件实体应该对扩展开放,而对修改关闭。 —- 开放/关闭原则(Bertrand Meyer)