您的位置:首页 > 移动开发 > Objective-C

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

2010-05-15 21:43 429 查看
这次要讨论在 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),选项如下图:





(2) 接着新增一个类别 Fraction,用来存放一个分数,类别名称就叫 Fraction。






(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) 接着就定义及实做 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:


执行结果如下图:




(二)、 使用协定(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) 接着我们为这个专案新增一个 protocol,名字就叫 AssistantProtocol,名字你可以取你喜欢的,只要你自己明白,这是一个 protocol 档。









(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 协定。





(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) 最后看看执行的结果





(三)、 使用继承(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) 最后是执行的结果:







(四)、 使用复合(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) 最后来看执行的结果。





未完待续,下次来谈一谈 Foundation……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: