Objective-C 2.0 笔记 (3) Objective-C 物件导向程式设计,类目、协定、继承及复合

这次要讨论在 Objective-C 可以用哪些方式,来进行物件导向的程式设计。包涵的主题有:

  • 类目(category)
  • 协定(protocol)
  • 继承(inheritance)
  • 复合(composite)
(一)、 使用类目(class category),来扩充现有的类别。
(1) Objective-C 提供一个很方便的机制 class category,让你可以不需用 inheritance,就可以扩充扩充现有的类别。

何时会你会选择用 class category 而不用 inheritance?当你发现,你只需要新增或是修改某些操作(method),你觉得用继承是杀鸡用牛刀。

另外一个情况,是当有不只一个以上的人,来实做 class 的介面,用 class category 可以用来划分分工的内容。
(2) 首先用 Xcode 新增一个专案 OOP1(Object Oriented Program #1),选项如下图:
1  2
(2) 接着新增一个类别 Fraction,用来存放一个分数,类别名称就叫 Fraction。
3
4
(3) Fraction 类别有两个成员变数, numberator 用来放分子,denominator 用来放分母。用 @property 跟 @synthesize 让 Objective-C 编译器,帮我们产生 get/set 程式码。另外提供  5 个操作,setTo:over: 来设定初始值,add 用来加总两个 Fraction 变数,reduce 用来化简分数,print 用来列印分数,convertToNum 把分数转换成浮点数。
1: //
2: //  Fraction.h
3: //  OOP1
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import 
10: 
11: 
12: @interface Fraction : NSObject 
13: {
14:   int      numerator;
15:   int      denominator;
16: }
17: 
18: @property int  numerator;
19: @property int  denominator;
20: 
21: -(void)      setTo: (int)n over: (int) d;
22: -(Fraction*)  add: (Fraction*) f;
23: -(void)      reduce;
24: -(double)    convertToNum;
25: -(void)      print;
26: 
27: @end
28: 
1: //
2: //  Fraction.m
3: //  OOP1
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "Fraction.h"
10: 
11: 
12: @implementation Fraction
13: 
14: @synthesize numerator, denominator;
15: 
16: -(void) setTo: (int) n over: (int) d
17: {
18:   numerator = n;
19:   denominator = d;
20: }
21: 
22: -(Fraction*) add: (Fraction*) f
23: {
24:   //
25:   // (a/b) + (c/d) = ((a*d) + (b*c)) / (b*d)
26:   //
27:   
28:   Fraction *result = [[Fraction alloc] init];
29:   
30:   result.numerator = (self.numerator * f.denominator) + (self.denominator * f.numerator);
31:   result.denominator = (self.denominator * f.denominator);
32:   
33:   [result reduce];
34:   
35:   return result;
36: }
37: 
38: -(void) reduce
39: {
40:   int u = numerator;
41:   int v = denominator;
42:   int temp;
43:   
44:   while (v != 0) 
45:   {
46:     temp = u % v;
47:     u = v;
48:     v = temp;
49:   }
50:   
51:   numerator /= u;
52:   denominator /= u;
53: }
54: 
55: -(double) convertToNum
56: {
57:   double result = (double) numerator / denominator;
58:   
59:   return result;
60: }
61: 
62: -(void) print
63: {
64:   NSLog(@" %i/%i", numerator, denominator);
65: }
66: 
67: @end
68: 

(4) 接着我们透过 class category 来扩充 Fraction,我们要为 Fraction class 新增 add,sub,mul,div,加减乘除四个操作。我们把这个 category 取名为 MathOps。跟新增 Fraction 类别的步骤相同,不过这次我们给的档名为 Fraction+MathOps ,这样的命名是惯例。
5
(5) 接着就定义及实做 Fraction (MathOps) 这个类目,请参阅下面的程式列表。这个作法,即使你没有 Fraction 类别的原始码的情况下,也适用。这个就是 Objective-C 所提供的弹性。

1: //
2: //  Fraction+MathOps.h
3: //  OOP1
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "Fraction.h"
10: 
11: 
12: @interface Fraction (MathOps)
13: 
14: -(Fraction*) add: (Fraction*) f;
15: -(Fraction*) sub: (Fraction*) f;
16: -(Fraction*) mul: (Fraction*) f;
17: -(Fraction*) div: (Fraction*) f;
18: 
19: @end
20: 
1: //
2: //  Fraction+MathOps.m
3: //  OOP1
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "Fraction+MathOps.h"
10: 
11: 
12: @implementation Fraction (MathOps)
13: 
14: -(Fraction*) add: (Fraction*) f
15: {
16:   // (a/b) + (c/d) = ((a*d) + (b*c)) / (b*d)
17:   
18:   Fraction *result = [[Fraction alloc] init];
19:   
20:   result.numerator = (self.numerator * f.denominator) + (self.denominator * f.numerator);
21:   result.denominator = self.denominator * f.denominator;
22:   
23:   [result reduce];
24:   
25:   return result;
26: }
27: 
28: -(Fraction*) sub: (Fraction*) f
29: {
30:   // (a/b) - (c/d) = ((a*d) - (b*c)) / (b*d)
31:   
32:   Fraction *result = [[Fraction alloc] init];
33:   
34:   result.numerator = (self.numerator * f.denominator) - (self.denominator * f.numerator);
35:   result.denominator = self.denominator * f.denominator;
36:   
37:   [result reduce];
38:   
39:   return result;
40: }
41: 
42: -(Fraction*) mul: (Fraction*) f
43: {
44:   // (a/b) * (c/d) = (a*c) / (b*d)
45:   
46:   Fraction *result = [[Fraction alloc] init];
47:   
48:   result.numerator = (self.numerator * f.numerator);
49:   result.denominator = self.denominator * f.denominator;
50:   
51:   [result reduce];
52:   
53:   return result;
54: }
55: 
56: -(Fraction*) div: (Fraction*) f
57: {
58:   // (a/b) / (c/d) = (a*d) / (b*c)
59:   
60:   Fraction *result = [[Fraction alloc] init];
61:   
62:   result.numerator = (self.numerator * f.denominator);
63:   result.denominator = self.denominator * f.numerator;
64:   
65:   [result reduce];
66:   
67:   return result;
68: }
69: 
70: @end
71: 

(6) 接着修改 OOP1 主程式,来测试我们的 Fraction (MathOps) 类目,是否按照我们的设计,进行运算。首先初始化两个 Fraction 变数,fraction1 跟 fraction2,然后一个设为 1/2,另一个设为 1/4,接着进行两个分数的加、减、乘、除。最后释放掉 fraction1 跟 fraction 两个变数。

1: #import "Fraction.h"
2: #import "Fraction+MathOps.h"
3: 
4: int main (int argc, const char * argv[]) 
5: {
6:     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
7: 
8:   Fraction *fraction1 = [[Fraction alloc] init];
9:   Fraction *fraction2 = [[Fraction alloc] init];
10:   Fraction *result;
11:   
12:   [fraction1 setTo: 1 over: 2];
13:   [fraction2 setTo: 1 over: 4];
14:   
15:   // compute (1/2) + (1/4)
16:   result = [fraction1 add: fraction2];
17:   [result print];
18:   [result release];
19:   
20:   // compute (1/2) - (1/4)
21:   result = [fraction1 sub: fraction2];
22:   [result print];
23:   [result release];
24:   
25:   // compute (1/2) * (1/4)
26:   result = [fraction1 mul: fraction2];
27:   [result print];
28:   [result release];
29:   
30:   // compute (1/2) / (1/4)
31:   result = [fraction1 div: fraction2];
32:   [result print];
33:   [result release];
34:   
35:   [fraction1 release];
36:   [fraction2 release];
37:   
38:     [pool drain];
39:     return 0;
40: }
41: 

执行结果如下图:
6 
(二)、 使用协定(protocol),来定义物件支间要如何来互动(interact)。

(1) Objective-C 的 protocol 实质上的意义,就像是 C++ 的 pure virtual class,或是 Java 的 interface。但是取 protocol 这个名称,却更传神。在物件导向的程式设计,有时候你根本不关心跟你互动的是何种物件,你关心的是这个物件,到底听不听得懂你说的话。打个比方,“黑猫白猫,能抓得到老鼠的,就是好猫”,甚至“只要能抓得到老鼠,就是小狗,也不错啊”。

(2) 还是有点搞不清楚 protocol 到底是怎么一回事,对不对?让我们用一个简单的例子,来示范如何使用 protocl。先假设你是一个老板(一个已经存在的物件),你要找一个助手(一个未知的物件),对助手当然会有要求(protocol),只要满足这个要求,你就录用,不然他就不能成为你的助手。

(3) 首先用 Xcode 新增一个专案 OOP2(Object Oriented Program #2)
2-1
(2) 接着我们为这个专案新增一个 protocol,名字就叫 AssistantProtocol,名字你可以取你喜欢的,只要你自己明白,这是一个 protocol 档。
2-2
2-3
(3) AssistantProtocol.h 里定义了合格的 Assistant 应该要会的事情。在这里,我们定义了,一个合格的 Assistant 应该要会 makePlan,updateSchedule,statusReport,然后 bootlick (拍马屁)是选项,并非绝对必要,最后还要 tellTheTruth。

1: //
2: //  AssistantProtocol.h
3: //  OOP2
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import 
10: 
11: 
12: @protocol AssistantProtocol
13: 
14: -(void) makePlan;
15: -(void) updateSchedule;
16: -(void) statusReport;
17: 
18: @optional
19: -(void) bootlick;
20: 
21: @required
22: -(void) tellTheTruth;
23: 
24: @end
25: 

(4) 接着我们新增一个类别 GoodAssistant,这是一个合格的 Assistant,符合 AssistantProtocol 的要求。注意,我们在 GoodAssistant 的介面宣告,用 ,让这个 class 满足 AssistantProtocol 协定。
2-4
(5) 然后我们就在 GoodAssist 这个 class 里,实做 AssistantProtocol 所需要的操作。

1: //
2: //  GoodAssistant.h
3: //  OOP2
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import 
10: #import "AssistantProtocol.h"
11: 
12: @interface GoodAssistant : NSObject 
13: {
14:   // nothing special here
15: }
16: 
17: @end
18: 
1: //
2: //  GoodAssistant.m
3: //  OOP2
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "GoodAssistant.h"
10: 
11: 
12: @implementation GoodAssistant
13: 
14: -(void) makePlan
15: {
16:   NSLog(@"make plan");
17: }
18: 
19: -(void) updateSchedule
20: {
21:   NSLog(@"update schedule");
22: }
23: 
24: -(void) statusReport
25: {
26:   NSLog(@"status report");
27: }
28: 
29: -(void) bootlick
30: {
31:   NSLog(@"bootlick");
32: }
33: 
34: -(void) tellTheTruth
35: {
36:   NSLog(@"tell the truth");
37: }
38: 
39: @end
40: 

(6) 接着我们新增一个 BadAssistant 类别,这个类别不满足 AssistantProtocol。

1: //
2: //  BadAssistant.h
3: //  OOP2
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import 
10: 
11: 
12: @interface BadAssistant : NSObject 
13: {
14:   // nothing special here
15: }
16: 
17: @end
18: 
1: //
2: //  BadAssistant.m
3: //  OOP2
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "BadAssistant.h"
10: 
11: @implementation BadAssistant
12: 
13: @end
14: 

(7) 接着我们新增一个 Boss 类别,这个 Boss 就是要按照 AssistantProtocol 的协定,来伺候的大爷。通常 protocol 协定,就是为这些 Boss 大爷而定的(不是为了 Assistant 助手这些小咖),这点抓到了,你大概就知道 protocol 是怎么一回事。Boss 他根据 AssistantProtocol 可以判断来服务的物件,是否够格,如果够格,就给他们点事情做。

1: //
2: //  Boss.h
3: //  OOP2
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import 
10: #import "AssistantProtocol.h"
11: 
12: 
13: @interface Boss : NSObject 
14: {
15:   // nothing special here
16: }
17: 
18: -(BOOL) IsAssistantQualified: (id) assistant;
19: -(void) AskAssistantToWork: (id) asssitant;
20: 
21: @end
22: 
1: //
2: //  Boss.m
3: //  OOP2
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "Boss.h"
10: 
11: 
12: @implementation Boss
13: 
14: -(BOOL) IsAssistantQualified: (id) assistant
15: {
16:   return [assistant conformsToProtocol: @protocol(AssistantProtocol)];  
17: }
18: 
19: -(void) AskAssistantToWork: (id) asssitant
20: {
21:   [asssitant makePlan];
22:   [asssitant updateSchedule];
23:   [asssitant statusReport];
24:   [asssitant bootlick];
25:   [asssitant tellTheTruth];
26: }
27: 
28: @end
29: 

(8) 最后来看主程式 OOP2 是如何用这些物件的,首先初始化一个 Boss 物件,一个 GoodAssistant 物件,及一个 BadAssistant 物件。接着让 boss 物件检查两个 assistant 物件,如果满足 AssistantProtocol 协定,就让物件做点事,如果不合格,就印出错误讯息。

1: #import 
2: #import "AssistantProtocol.h"
3: #import "GoodAssistant.h"
4: #import "BadAssistant.h"
5: #import "Boss.h"
6: 
7: int main (int argc, const char * argv[]) 
8: {
9:     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
10: 
11:   Boss *boss = [[Boss alloc] init];
12:   GoodAssistant *assistant1 = [[GoodAssistant alloc] init];
13:   BadAssistant *assistant2 = [[BadAssistant alloc] init];
14:   
15:   NSLog(@"-- if assistant1 is qualified then ask it to work --");
16:   
17:   if ([boss IsAssistantQualified: assistant1] == YES)
18:     [boss AskAssistantToWork: assistant1];
19:   else
20:     NSLog(@"assistant1 is not qualified.");
21: 
22:   NSLog(@"-- if assistant2 is qualified then ask it to work --");
23:   
24:   if ([boss IsAssistantQualified: assistant2] == YES)
25:     [boss AskAssistantToWork: assistant2];
26:   else
27:     NSLog(@"assistant2 is not qualified.");
28:   
29:   [boss release];
30:   [assistant1 release];
31:   [assistant2 release];
32:   
33:     [pool drain];
34:     return 0;
35: }
36: 

(9) 最后看看执行的结果
2-7
(三)、 使用继承(inheritance),站在巨人的肩膀上,写程式。

(1) 继承(inheritance)是物件导向程式设计,常用的一种实做的方法。你可以这样想,有许多事先已经写好的类别,来处理各式各样的事情,有时候直接拿来用,就对了。但是有时候,这些现有的类别,就是少那么一点什么,或是有些地方,跟你要的结果不一样。这时候你可以继承那些类别,新增或是修改你要的部份。这样对比你全部自己写还快。另外,有时候有两个或是两个以上的类别,他们有许多的程式码,是重复而可以互相共用的,这时候把共用的部份,抽出来,变成一个父类别,不但可以让程式码变小,还可减少错误发生的机会。

(2) 用 Xcode 新增一个专案 OOP3 (Object Oriented Program #3),然后新增 Rectangle 类别,有两个成员变数 width,跟 height。另外有三个操作 setWidth:andHeight: 用来设四角形的宽跟高,area 用来求四边形的面积,perimeter 用来求四边形的周长。

1: //
2: //  Rectangle.h
3: //  OOP3
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import 
10: 
11: 
12: @interface Rectangle : NSObject 
13: {
14:   double width;
15:   double height;
16: }
17: 
18: @property double width;
19: @property double height;
20: 
21: -(void)    setWidth: (double) w andHeight: (double) h;
22: -(double)  area;
23: -(double)  perimeter;
24: 
25: @end
26: 
1: //
2: //  Rectangle.m
3: //  OOP3
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "Rectangle.h"
10: 
11: 
12: @implementation Rectangle
13: 
14: @synthesize width, height;
15: 
16: -(void) setWidth: (double) w andHeight: (double) h
17: {
18:   width = w;
19:   height = h;
20: }
21: 
22: -(double) area
23: {
24:   return (width * height);
25: }
26: 
27: -(double) perimeter
28: {
29:   return (2 * (width + height));
30: }
31: 
32: @end
33: 

(3) 接着新增一个类别 Square 继承 Rectangle,但是多了 setSide 来设正方形的边长,及 side 来取得正方形的边长。

1: //
2: //  Square.h
3: //  OOP3
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "Rectangle.h"
10: 
11: 
12: @interface Square : Rectangle
13: {
14: 
15: }
16: 
17: -(void) setSide: (double) side;
18: -(double) side;
19: 
20: @end
21: 
1: //
2: //  Square.m
3: //  OOP3
4: //
5: //  Created by Chou Shunyuan on 5/15/10.
6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
7: //
8: 
9: #import "Square.h"
10: 
11: 
12: @implementation Square
13: 
14: -(void) setSide: (double) side
15: {
16:   [self setWidth: side andHeight: side];
17: }
18: 
19: -(double) side
20: {
21:   return width;
22: }
23: 
24: @end
25: 

(4) 在主程式 OOP3 中,我们初始化了一个四边形 5 x 10,及一个正方形 10 x 10,然后列印出场方形,及正方形的面积及周长。

1: #import "Rectangle.h"
2: #import "Square.h"
3: 
4: int main (int argc, const char * argv[]) 
5: {
6:     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
7:   
8:   Rectangle *rectangle = [[Rectangle alloc] init];
9:   Square *square = [[Square alloc] init];
10:   
11:   [rectangle setWidth: 5.0 andHeight: 10.0];
12:   NSLog(@"the area of %g x %g rectangle = %g", 
13:       rectangle.width,
14:       rectangle.height,
15:       [rectangle area]);
16:   
17:   NSLog(@"the perimeter of %g x %g rectangle = %g", 
18:       rectangle.width,
19:       rectangle.height,
20:       [rectangle perimeter]);
21:   
22:   [square setSide: 10.0];
23:   NSLog(@"the area of %g x %g square = %g",
24:       [square side],
25:       [square side],
26:       [square area]);
27:   
28:   NSLog(@"the perimeter of %g x %g square = %g",
29:       [square side],
30:       [square side],
31:       [square perimeter]);
32:   
33:   [rectangle release];
34:   [square release];
35: 
36:     [pool drain];
37:     return 0;
38: }
39: 

(5) 最后是执行的结果:
3-1

(四)、 使用复合(composite),就像组合乐高积木,让写程式更简单。

(1) 复合(composite)其实不是 Objective-C 的语言特色,而是物件导向程式设计,用来化繁为简的一个作法。想像有一天,你有一个类别,继承了超过 10 个以上的子类别,会发生什么事情?

首先,各个类别的成员变数(member variable)的名字有可能会重复?各个类别的操作(method)的名字会重复?

接着,因为继承了很多类别,你的成员变数,跟操作的数量,是不是就很多,光是找名字,就累人了。当这种情形发生,用 composite 可以把类别阶层打平,方便管理。

composite 的作法,还有一个优势,就是你可以在执行时在合成你的物件,而继承是你在定义你的类别时,就已经决定。composite 在实际应用上,用得很广泛。

(2) 实际的例子如下,首先用 Xcode 建立一个新的专案 OOP4 (Object Oriented Program #4),然后新增一个类别 Rectangle 如以下列表。

  1: //
  2: //  Rectangle.h
  3: //  OOP4
  4: //
  5: //  Created by Chou Shunyuan on 5/15/10.
  6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
  7: //
  8: 
  9: #import 
 10: 
 11: 
 12: @interface Rectangle : NSObject 
 13: {
 14:   double width;
 15:   double height;
 16: }
 17: 
 18: @property double width;
 19: @property double height;
 20: 
 21: -(void)    setWidth: (double) w andHeight: (double) h;
 22: -(double)  area;
 23: -(double)  perimeter;
 24: 
 25: @end
 26: 
  1: //
  2: //  Rectangle.m
  3: //  OOP4
  4: //
  5: //  Created by Chou Shunyuan on 5/15/10.
  6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
  7: //
  8: 
  9: #import "Rectangle.h"
 10: 
 11: 
 12: @implementation Rectangle
 13: 
 14: @synthesize width, height;
 15: 
 16: -(void) setWidth: (double) w andHeight: (double) h
 17: {
 18:   width = w;
 19:   height = h;
 20: }
 21: 
 22: -(double) area
 23: {
 24:   return (width * height);
 25: }
 26: 
 27: -(double) perimeter
 28: {
 29:   return (2 * (width + height));
 30: }
 31: 
 32: @end
 33: 

(3) 接着我们新增一个类别 Square,跟之前版本不一样,这次的类别 Square 并没有继承 Rectangle,而是改成用一个成员变数 rectangle 来保存一个 Rectangle 类别的 instance 指标。特别注意,我们覆写了 init,在 init 中,我们初始化了 rectangle 变数。同时,我们也覆写了 dealloc,当 square 被释放前,用来释放掉我们所创建的 rectangle 变数。

  1: //
  2: //  Square.h
  3: //  OOP4
  4: //
  5: //  Created by Chou Shunyuan on 5/15/10.
  6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
  7: //
  8: 
  9: #import 
 10: #import "Rectangle.h"
 11: 
 12: 
 13: @interface Square : NSObject
 14: {
 15:   Rectangle *rectangle;
 16: }
 17: 
 18: -(id)    init;
 19: -(void)    dealloc;
 20: 
 21: -(void)    setSide: (double) side;
 22: -(double)  side;
 23: 
 24: -(double)  area;
 25: -(double)  perimeter;
 26: 
 27: @end
 28: 
  1: //
  2: //  Square.m
  3: //  OOP4
  4: //
  5: //  Created by Chou Shunyuan on 5/15/10.
  6: //  Copyright 2010 __MyCompanyName__. All rights reserved.
  7: //
  8: 
  9: #import "Square.h"
 10: 
 11: 
 12: @implementation Square
 13: 
 14: -(id)init 
 15: {
 16:   if (self = [super init]) 
 17:   {
 18:     rectangle = [[Rectangle alloc] init];
 19:   }
 20:   
 21:   return self;
 22: }
 23: 
 24: -(void) dealloc
 25: {
 26:   [rectangle release];
 27:   [super dealloc];
 28: }
 29: 
 30: -(void) setSide: (double) side
 31: {
 32:   if (rectangle)
 33:   {
 34:     [rectangle setWidth: side andHeight: side];
 35:   }
 36: }
 37: 
 38: -(double) side
 39: {
 40:   if (rectangle)
 41:   {
 42:     return rectangle.width;
 43:   }
 44:   
 45:   return 0;
 46: }
 47: 
 48: -(double) area
 49: {
 50:   if (rectangle)
 51:   {
 52:     return [rectangle area];
 53:   }
 54:   
 55:   return 0;
 56: }
 57: 
 58: -(double) perimeter
 59: {
 60:   if (rectangle)
 61:   {
 62:     return [rectangle perimeter];
 63:   }
 64:   
 65:   return 0;
 66: }
 67: 
 68: @end
 69: 

(4) 特别注意,Square 类别,在计算面积,及计算周长时,是透过内部的 rectangle 物件,来计算的。你或许会觉得这是多此一举,用继承的方式,实做上似乎比较单纯。但是这是因为我所举的例子,所用到的类别 Rectangle 太简单了。以 composite 的方式,无论多复杂的物件,大概都是这样,依样画葫芦,就算有 100 个类别也是一样。同时,你只需要提供有用到的操作,没用到的可以忽略。

(5) 最后来看执行的结果。

1

未完待续,下次来谈一谈 Foundation……

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值