`
wenrunchang123
  • 浏览: 249345 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

初步熟悉Objective C面向对象

 
阅读更多

年尾有点忙,objctive C的学习都放下了,趁有空补下课^_^

 

一、间接的理解

       在编程界有句话,“只有多添加一个间接层,计算机科学没有解决不了的问题”。其实间接很简单,就是说不在代码中直接使用某个值,而使用指向该值的指针。

       生活中的例子:你可能不知道KFC的电话号码,但你可以通过网上查找KFC的电话号码,使用网上查找实际就是一种间接地方式。

        间接在程序上有多种表现方式,就例如变量式的间接、文件式间接、参数式间接。

 

二、OOP世界中的间接使用

       其实OOP真正的革命性就是在调用代码中使用间接。

       首先来个过程式编程的例子,好让大家容易理解OOP的思想。

       

#import <Foundation/Foundation.h>

typedef enum{
	kCircle,
	kRectangle,
	kOblateSpheroid
} ShapeType;

typedef enum{
	kRedColor,
	kGreenColor,
	kBlueColor
} ShapeColor;

typedef struct{
	int x, y, width, height;
} ShapeRect;

typedef struct{
	ShapeType type;
	ShapeColor fillColor;
	ShapeRect bounds;
} Shape;

void drawShapes(Shape shapes[], int count){
	int i;
	for(i = 0; i < count; i++){
		switch (shapes[i].type) {
			case kCircle:
				drawCircle(shapes[i].bounds, shapes[i].fillColor);
				break;
			case kRectangle:
				drawRectang(shapes[i].bounds, shapes[i].fillColor);
				break;
			case kOblateSpheroid:
				drawEgg(shapes[i].bounds, shapes[i].fillColor);
				break;
			default:
				break;
		}
	}
}

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 drawRectang(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 drawEgg(ShapeRect bounds, ShapeColor fillColor){
	NSLog(@"drawing a circle at (%d %d %d %d) in %@", bounds.x, bounds.y, bounds.width, bounds.height, colorName(fillColor));
}

NSString *colorName(ShapeColor colorName){
	switch(colorName){
		case kRedColor :
			return @"red";
			break;
		case kGreenColor :
			return @"green";
			break;
		case kBlueColor:
			return @"blue";
			break;
	}
	return @"no clue";
}

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, 600};
	shapes[1].type = kCircle;
	shapes[1].fillColor = kRectangle;
	shapes[1].bounds = rect1;

	ShapeRect rect2 = {15, 18, 37, 29};
	shapes[2].type = kOblateSpheroid;
	shapes[2].fillColor = kBlueColor;
	shapes[2].bounds = rect2;

	drawShapes(shapes, 3);
	return (0);
}

    上面的代码灰常简单明了,但有一个问题是程序的扩展和维护变得很困难,如果我们多加一种类型,必须在项目中至少4个不同位置修改程序才能完成该任务。

 

以下说的OOP完美解决了这些问题,它以数据为中心,函数为数据服务。

void drawShapes(id shapes[], int count){
	int i;
	
	for(i = 0; i < count; i++){
		id shape = shapes[i];
		[shape draw];
	}
}

       上面的代码可能很多同学都感觉很奇怪,一般来说方括号在C语言中代表数组,在Objective C中,方括号还有其他的意思:它们通知某个对象该做什么。在方括号内,第一项是对象,其余部分是你需要对象执行的操作。在本例中,我们通知名称为shape的对象执行draw操作。如果shape是圆形,我们会得到圆形;如果shape是矩形,我们会的到矩形。

        在Objective-C中,通知对象执行某种操作称为“发送消息”或者“调用方法”。代码中[shape draw]表示shape对象发送draw消息。

        还有一个比较奇怪的地方就是id,id是一种泛型,用于表示任何种类的对象。实际id是一个指针,指向其中的某个结构。

 

 三、面向对象的例子

以下是CirCle接口的声明

@interface Circle : NSObject{
	ShapeColor fillColor;
	ShapeRect bounds;
}

- (void) setFillColor : (ShapeColor) fillColor;
- (void) setBounds : (ShapeRect) bounds;
- (void) draw;

@end

 @interface”告诉编译器这是objective C的声明的接口“。

 

Circle对象需要的各种数据成员:

{

      ShapeColor fillColor;

      ShapeRect bounds;

}

 

- (void) setBounds: (ShapeRect) bounds;

奇葩的objective,在方法声明的前面还多加个”-“,短线后面是方法的返回类型,位于圆括号中。接着后面的你们都懂的,就是参数的声明。

 

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

 

跟声明接口一样,实现的也需要以@implementaction开头,结尾使用@end。

实际上objectvie - c中调用方法是,一个名为self的秘密隐藏参数被传递给接收对象。

以上例子中的fillColor = c,可以写成self->fillCOlor = c;

 

 接下来最后一步实例化对象

实例化对象时,需要分配内存,然后这些内存被初始化并保存一些有用的默认值。

int main(int argc, const char * argv[]){
	id shapes[3];
	
	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, 19, 37, 29};
	shapes[2] = [OblateShereoid new];
	[shapes[2] setBounds : rect2];
	[shapes[2] setFillCOlor : kBlueColor];
	
	drawShapes(shapes, 3);
	
	return (0);
}

 

看上去,oop例子中的main方法跟过程化例子的main有点相似,oop例子中含有id数组,而不是shapes数组,创建对象时都需要发送new消息。

 

如果我们在程序上再添加一种类型,只需实现接口就可以扩展。

@implementation Triangle

-(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));
}

 

 总结:

过程化编程:函数第一,数据第二

面向对象编程:数据第一、函数第二

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics