极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 18965|回复: 3

Processing官网学习部分原文翻译——对象object

[复制链接]
发表于 2012-11-8 21:56:55 | 显示全部楼层 |阅读模式
面向对象编程
本手册适用于Processing1.1及以上版本,如果你发现有任何错误或者有任何建议,请联系我们。本参考手册源自《Learning Processing》一书,由Daniel Shiffman编写,Morgan Kaufmann出版社出版,Elsevier公司2008版权。版权所有。

沿着OOP(面向对象编程)往下走
在我们开始详细的检查面向对象编程(OOP)是如何工作的之前,让我们先弄一个简短的概念来讨论“对象”。想象一下如果你不用Processing编程,但是你一天也写了一个程序,如果你愿意可以使一个指令列表。他可能这样开始:
  • 醒过来
  • 整杯咖啡(或者茶)
  • 吃早餐:谷类、蓝莓喝一些豆奶
  • 乘坐地铁

这里所涉及到的是什么?具体地说,什么东西参与进来了?首先,显然这不会立即显现出我们如何写出上述指令,最主要的是你,只有一个人在做,一个人!你表现出一些属性。你注意某一方式,也许你有棕色的头发,戴眼镜,显得有点书呆子气。你同样有能力做些事情,例如醒来(想必你也可以睡觉),吃东西或者坐地铁。一个对象就像你一样,一个有属性并且可以做东西的东西。
但是这跟编程有么子关系?对象的属性是变量;对象可以做的是函数。面向对象编程与所有的编程原理的数据和功能是紧密相连。
让我们画出一个简单的人的对象的数据和函数:
人*数据
  • 身高
  • 体重
  • 性别
  • 眼睛颜色
  • 头发颜色

人*函数
  • 睡觉
  • 醒来
  • 吃饭
  • 乘坐某种交通工具

现在在我们得到更多深层次的东西前,我们需要采取一个简短的超自然题外话。上面的结构不是一个人本身;它只是在人后面简单描述了一个想法,或者概念。他描述了人去做什么。作为一个人,有身高、头发,要睡觉、吃饭等等。这个是和编程对象至关重要的区别。这个人类模版被认为是一个类。一个类不同于一个对象。你是一个对象。我也是一个对象,在地铁里的那个家伙也是一个对象。阿尔伯特•爱因斯坦也是一个对象。我们都是人,一个人的想法在真实世界中的实例。
想象一个曲奇成型刀,一个曲奇成型刀制作了曲奇,但是它本身并不是一个曲奇。这个曲奇成型刀是一个类,曲奇是对象。
使用对象
在我们看一个实实在在的类之前,让我们简单学学怎么在主程序(即setup()和draw())中使用,让世界变得更美好。
考虑在窗口中水平移动矩形的简单草图的伪代码(我们可以想象这个矩形就是一个汽车)。
Data (全局变量):
  • 汽车颜色。.
  • 汽车X轴坐标.
  • 汽车y轴坐标.
  • 汽车x轴速度.


Setup:
  • 初始化汽车颜色.
  • 初始化汽车起始点位置
  • 初始化汽车速度


Draw:
  • 填充背景
  • 在相应位置用颜色显示汽车
  • 更具速度增加汽车位置


为了执行这些伪代码,我们需要在程序顶端定义全局变量,在setup()中初始化它们,并在draw()中呼叫函数执行并显示汽车。像这样:

[pre lang="processing" line="1"]color c = color(0);
float x = 0;
float y = 100;
float speed = 1;

void setup() {
  size(200,200);
}

void draw() {
  background(255);
  move();
  display();
}

void move() {
  x = x + speed;
  if (x > width) {
    x = 0;
  }
}

void display() {
  fill(c);
  rect(x,y,30,10);
}[/code]
面向对象编程允许我们将所有的变量和函数从主程序中弄出来,并将他们储存在一个汽车对象中。汽车对象会知道它的数据——颜色、位置、速度。对象会知道他能做的东西,用这种方法(函数在对象中)——汽车就可以驱动并且它可以显示。
用面向对象设计,伪代码可以改成这样:
Data(全局变量)
  • 汽车对象

Setup:
  • 初始化汽车对象

Draw:
  • 填充背景
  • 显示汽车对象
  • 驱动汽车对象

注意我们从第一个例子中移动了所有的全局变量。代替了汽车颜色、汽车位置和汽车速度这些单独变量,我们现在只有一个变量,一个汽车变量!并且替代了三个变量的初始化,我们现在只初始化一个东西,汽车对象。那些变量哪儿去了呢?他们任然存在,只是他们现在住在汽车对象中(会在汽车类中被定义,一会儿他们也会去。)
伪代码之后,草图的实际部分也许是这样的:

[pre lang="processing" line="1"]Car myCar;

void setup()  {   
  myCar = new Car();   
}   

void draw()  {   
  background(255);   
  myCar.drive();   
  myCar.display();   
}           [/code]
现在我们要进入代码细节方面,但是在我们做之前,让我们看看这个汽车类是怎么写的。
书写模型(或者写曲奇成型刀,很别扭哦!)

这个简单的汽车例子演示了如何使用清晰、可读的代码在Processing中使用对象。最难的工作进入到了书写对象末班,即类本身。当你初次学习关于面向对象编程时,通常是一个有用的没有对象的程序书写练习,并且不改变其函数,重写它的使用对象。我们会这样弄汽车例子,用面向对象的方式重建相同外观和动作。
所有的类必须包括四个部分:名称,数据,构造函数和方法。(从技术上来说,唯一实际需要的部分是类的名称,但是面向对象编程的关键点包括所有部分。)
这是一个我们可以做的简单的非面向对象草图,我们将其放到一个能够做成的汽车对象的汽车类里面。


元素名称:指定的名称是“你想用的任何类名称”。然后我们附上所有的类代码放在声明后面的括号里面。一般类名称用大写(以区别于变量名,变量名通常用小写)。
数据:类的数据是一个变量集合。这些变量通常被称为实例变量,因为每个对象的实例包含这组变量。
构造函数:构造函数是类中的一个特殊函数,这个类既是创建的实例对象本身。这里给你介绍如何设置对象。就像Processing的setup()函数一样,只是在这儿用来在草图中创建一个单独的对象,不管在哪儿通过这个类创建的对象。通常和类有相同的名称,即通过调用新的运算符的名称:“Car myCar = new Car();”。(PS车,我的车=我的新车!什么逻辑啊!)
功能:我们可以通过书写方法添加功能到我们的对象中。
注意,类代码以自己的模块形式存在,可以放在setup()和draw()以外的任何地方。

[pre lang="processing" line="1"]void setup() {
}
void draw() {
}
class Car {
}        [/code]
使用对象:细节方面
早前,我们用很快的速度在对象尽可能简化Processing草图的主函数部分(即setup()和draw())。

[pre lang="processing" line="1"]// 第一步,声明一个对象
Car myCar;

void setup()  {   
  // 第二步,初始化对象
  myCar = new Car();   
}   

void draw()  {   
  background(255);  
  // 第三步,对象的使用方法
  myCar.drive();   
  myCar.display();   
}      [/code]
让我们看看上面三个步骤背后的细节,通过一个在你的草图中使用对象的概述。
第一步,声明一个对象变量
一个变量总是由指定的类型和名称来声明。有一个原始的数据类型,如整数,它看起来像这样:

[pre lang="processing" line="1"]//变量声明
int var;  // type name[/code]
原始数据类型是比较奇怪的信息:整数、浮点数、字符等。声明变量和用对象差不多。不同之处在于这儿的类型是类名称,有时候我们这样构成,这儿就是“Car车”。
顺便说一句,对象不是基本体,要考虑复杂的数据类型。(这是因为信息存储的多个区域:数据和功能。基本体只能存储数据。)
第二步,初始化对象
为了初始化变量(即给它一个初始值),我们用一个固定的运算——变量等于什么东西。和一个基本体(如整型),看起来这样:

[pre lang="processing" line="1"]// 初始化变量
var = 10;  // var equals 10 [/code]
初始化对象要复杂点。不是简单的给他一个值,像一个整型或者浮点型数,我们必须构造对象。一个对象由new操作符弄出来。
[pre lang="processing" line="1"]// 对象初始化
myCar = new Car(); // new操作符是用来做一个新的对象。[/code]
在上面的示例中,“myCar”是一个对象变量名,“=”表示我们设置它等于什么,一些作为Car对象的示例。实际上我们这里做的是初始化Car对象。当你初始化一个基本体变量,如一个整型,你只是设置它等于一个数。但是一个对象可能包含很多个数据。再看看Car类,我们看出这行代码调用构造函数,一个名为Car()的特殊函数初始化所有的对象变量,并且确保Car对象做好准备。
另外一件事;关于基本体整型“var”,如果你忘记对其初始化(这是他等于10),Processing会讲一个默认值分配给它,即0。一个对象(比如“myCar”),却没有默认值。如果你忘了初始化对象,Processing给他一个为空值,空即是没有。不是零,也不是负数,就是没有,啥都没有。如果在消息窗口遇到一个错误,说“Null Pointer Exception空指针异常”(这是一个很常见的错误),这个错误就很有可能是忘了初始化对象而导致的。
第三步,使用对象
一旦你成功的声明并初始化变量后,我们就可以使用它了。使用对象的话涉及到对象内置的调用函数。人的对象可以吃,车的对象可以开,狗的对象可以叫。对象内部的调用函数是通过点语法来完成的:变量名.对象函数(函数参数);
在汽车类中,没有一个变量函数有参数,因此他看起来是这样的:

[pre lang="processing" line="1"]// 用点语法调用函数
myCar.drive();   
myCar.display(); [/code]

构造函数参数
这是一个有用的简化对于我们学习面向对象编程基础。尽管这样,这也有一个比上面代码严重点的问题。如果我们想编写有两个汽车对象的程序咋办?

[pre lang="processing" line="1"]// 创建两个汽车对象
Car myCar1 = new Car();   
Car myCar2 = new Car();[/code]
这样完成我们的目标;代码将生成两个汽车对象,一个存储在变量myCar1一个存储在变量myCar2.然而,如果你研究汽车类,你会注意到这两个汽车是一样的:每个都图上白色,从屏幕中间开始,有一个为1的速度。在英语中,上面写成:
做一个新车。
我们会这样替换:
做一个新的红色的车,在(0,10)位置,速度为1.
同样我们还可以这样说:
做一个新的蓝色的车,在(0,100)位置,速度为1
我们可以通过设置构造函数式里面的参数。

[pre lang="processing" line="1"]Car myCar = new Car(color(255,0,0),0,100,2);[/code]
构造函数必须将这些参数从新设置:
[pre lang="processing" line="1"]Car(color tempC,float tempXpos,float tempYpos,float tempXspeed){
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
xspeed = tempXspeed;
}[/code]
根据我的经验,使用构造函数参数来初始化对象变量可能会有点迷惑。不应责备自己。代码是有点怪并且看起来非常沉余:“需要为每一个我想用的变量设置函数构造参数?”
不过这是一个为了学习相当重要的技能,并且最终,会成为使面向对象编程更强大的一个东西。但是现在,可能会感觉痛苦。让我们看看参数是怎么样在上下文中工作的。


参数是函数体重的基本变量,在函数调用时得到值得填充。在例子中,他们只有一个目的,在对象中初始化这个变量。这些是有用的变量:扯得实际颜色、车的实际x轴位置等等。构造函数的参数只是暂时的,通过一个来自于对象自己造的对象里面的值单独存在。
这允许我们我们使用同样的构造函数来制造各种各样的对象。你可能只是临时用这个词作为参数名称,以此提醒自己是怎么回事(c和tempC)。你会在很多例子中看到程序员使用下划线(c和c_)。当然,你可以用你想的任何名称命名。然而,明智的做法是选择一个对你来说有意义的名字,后面也要保持一致。现在我们可以看看一些有多个对象实例的相同的草图,每个都有独特性能。

[pre lang="processing" line="1"]// 例子:两个汽车对象
Car myCar1;
Car myCar2; // Two objects!

void setup() {
  size(200,200);
  // 构造对象的时候参数要放到括号里面去
  myCar1 = new Car(color(255,0,0),0,100,2);
  myCar2 = new Car(color(0,0,255),0,10,1);
}

void draw() {
  background(255);
  myCar1.drive();
  myCar1.display();
  myCar2.drive();
  myCar2.display();
}

// 即使这儿有多个对象,我们也只需要一个类
// 不管我们做了多少个曲奇,我们只需要一个曲奇刀
class Car {
  color c;
  float xpos;
  float ypos;
  float xspeed;

  // 构造函数由参数定义
  Car(color tempC, float tempXpos, float tempYpos, float tempXspeed) {
    c = tempC;
    xpos = tempXpos;
    ypos = tempYpos;
    xspeed = tempXspeed;
  }

  void display() {
    stroke(0);
    fill(c);
    rectMode(CENTER);
    rect(xpos,ypos,20,10);
  }

  void drive() {
    xpos = xpos + xspeed;
    if (xpos > width) {
      xpos = 0;
    }
  }
}[/code]
对象也就是个数据类型
假如这是你第一次用面向对象编程经历,请放松点。这个例子只使用一个类,最多两个或者三个这种类的对象。事实上没有实际的限制。一个Processing草图可以包括很多个类,你想写多少就可以有多少。
如果你先写一个太空入侵者游戏,例如,你会创建一个宇宙飞船类,敌人类和一个子弹类,在你的游戏中的实体使用对象。
此外,尽管不是基本体,类与整型和浮点型一样都是数据类型。由于类是由数据组成的,因此对象可以包含其他对象!例如,假设你刚刚完成叉子和勺子类的程序。往前到PlaceSetting类,你会想要在类自身中包括叉子对象和勺子对象的变量。这是非常合理的,并且在面向对象编程中很普遍。

[pre lang="processing" line="1"]class PlaceSetting  {      
  Fork fork;   
  Spoon spoon;     
  PlaceSetting()  {   
    fork = new Fork();   
    spoon = new Spoon();   
  }   
}  [/code]
对象,和任何数据类型一样,可以作为一个参数传递给函数。在太空入侵游戏例子中,如果宇宙飞船在敌人中射子弹,我们可能会想在敌人类中写一个函数,来确定敌人本子弹射中。
[pre lang="processing" line="1"]void hit(Bullet b)  {   
  // 代码用来确定
  // 子弹射中敌人
}  [/code]
当一个基本体(整型,浮点型等)进入到函数,副本就产生了。对于对象,不是这样的情况,结果更直观些。如果在它传递到函数后对象做了改动,这个改变就会影响整个草图中任何地方使用的这个对象。通过盈盈而不是拷贝所知,提及到实际对象本身传递到函数。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2012-11-8 22:08:11 | 显示全部楼层
顶!{:soso_e179:}{:soso_e179:}
回复 支持 反对

使用道具 举报

发表于 2012-11-8 22:31:39 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2014-11-27 18:47:27 | 显示全部楼层
这个必须顶,现在在学习《爱上processing》,刚开始总是觉得类,对象之类的都看不懂,现在看看这个帖子,感觉自己思路清晰多了,新人求以多指教,非常感谢前辈们的分享,希望以后还会有更多详细的学习心得或者作品与我们这些菜鸟分享~~~~~
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-18 15:00 , Processed in 0.052264 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表