Ruby 部分
Ruby 有如下重要特性
- 纯面向对象(pure OOP):Ruby 中的所有值都是对象,每个表达式执行后都得到一个对象(有些面向对象语言不是这样,比如 Java 中的整型、布尔型、浮点数字面量都不是对象)
- 基于类的面向对象(class-based):每个对象都是类的实例。类决定了对象所拥有的方法。(有些语言也不是基于类的,典型的如 JavaScript 是基于原型的)
- 混入(mixin):多重继承(C++)与接口(Java)之间的一个折中。Ruby 中每个类都只有一个父类,但是可以有任意数量的混入,不像接口,它们可以定义方法(而不只是要求某个方法要存在)。
- 动态:Ruby 允许在任意对象上以任意参数调用任意方法,还可以在运行时改变类和对象的属性
- 反射(reflection):可以在运行时知道对象的类是什么,有哪些方法
- 闭包(block and closure):block 几乎就是闭包并且可以方便地用来使用库中的高阶函数,由于众多迭代函数的存在,Ruby 中也几乎不会显示使用循环。Ruby 中也有完整的闭包(proc)
- 脚本语言(script language):脚本语言没有一个精确的定义,它意味着能够快速地写出简短的程序,方便地操作文件和字符串,较少考虑性能
- 流行于 Web 应用开发:Ruby on Rails 是一个非常流行的服务端框架
Class-Based OOP 基于类的面向对象
面向对象有如下几条规则:
- 所有变量都是对象的引用
- 给定一个对象,可以通过调用它的方法与之交流,也可以被称为发送消息
- 每个对象都有其私有的状态,只有对象自身的方法才能访问和修改状态
- 每个对象都是类的实例
- 类决定了对象的行为,类包含了方法的定义,它决定了对象如何处理它收到的调用(消息)
在另一些面向对象语言比如 Java/C# 中,大部分的规则都被实现了,然而 Ruby 给出了一个更完整的实现。 例如:
- 一些字面量在 Java/C# 中不是对象,违反了规则1
- Java/C# 中有
public
的属性,违反了规则3
Calling Methods 调用方法
e0.m(e1, e2, ...)
与其他语言类似,首先得到表达式 e0, e1, e2…
的结果 obj0, obj1, obj2, …
,然后以 obj1, obj2, …
调用 obj0
的方法 m
。方法调用另一种普遍的说法是消息传递,即向 obj0
传递了消息 m
,附带 obj1, obj2, …
为参数,这种说法“更面向对象”,因为我们不关心接受者 obj0
是怎样实现的,只关心它能够接受并处理消息
Instance Variables 实例变量与类变量
一个对象有对应的定义了方法的类,也有它自己的实例变量,可以持有值。这在 Java/C#/C++ 中称为域(fields)(或者属性?),不同的是,在 Ruby 中没有专门的声明一个对象所拥有的实例变量,当需要添加一个实例变量的时候,只要相应地赋值就可以。对应的,Java/C#/C++ 中有静态方法与静态变量,Ruby 中也有类变量与类方法,即被所有该类的实例共享。
# instance varible
@foo # getter
@foo= newValue # setter, will be created if not exist
# class varible
@@foo
Duck Typing 鸭子类型
If it walks like a duck and quacks like a duck, then it’s a duck.
言外之意是,没有理由去考虑那究竟是不是一只鸭子。在 Ruby 中,只要对所有消息的反应符合预期(比如会叫、会走),消息接受者(调用方法的对象)的类(比如 Duck
类)就不重要。面向对象更关心的是,能够“做什么”,而不在于“是什么”。
鸭子类型利于代码的重用,使得客户端可以使用“假”鸭子而仍然使用你的代码。但它的缺陷在于,我们只知道某个方法的实现,尤其是要传递什么消息给什么对象。比如,如果假定 i
是一个数,在没有被重写的情况下,我们知道 i + i
可以替换成 i * 2
或者 2 * i
,但是如果只假定 i
有一个名叫 +
的方法,它可以接受自身作为参数,那我们就无法做出上述替换,因为我们不知道 i
有没有 这个方法,也不知道 2
有没有 这个方法,是不是能接受 i
作为参数。
Override and Dynamic Dispatch 重写与动态分配
TODO
Mixin 混入
TODO