Mark24
Ruby中的方法我的总结
一切围绕方法的哲学
Ruby的一切,可以说是 —— 一切围绕方法。
面向对象是 数据+方法 的封装。而Ruby的变量不像JavaScript、Python允许自由的访问,必须在方法中通过设置 getter、setter来进行访问。可以说 方法是 Ruby工作的基石。
Ruby的方法有三大部分组成:
- 实例方法
- 类方法/单例方法
- 匿名函数方法
简单建立起概念,这三个基本方法,有自己的内涵边界。下面分别说明。
实例方法和类方法/单例方法,一起构成了面向对象系统
1.实例方法,非常容易理解。就是一般意义上的面向对象的为生成实例准备的方法。
表现形式是 class中直接定义的 def 方法。
1.1 实例方法和 inlcude
1) 继承关系 可以把一组方法,放入模块 比如 module B,然后 比如 class A include B。 这样在祖先链上会形成 A -> B 的关系。
1.2 搜索方法
实例搜索方法,当在A中无法找到的时候,会搜索B。
优先级顺序可以从 instance.class.ancestors 的返回中查看
1.3 覆盖方法
如果在A中定义的实例方法,会覆盖祖先方法,或者 module的mixin方法。
2.类方法/单例方法
严格意义上来说,应该是单例方法。
在类中,有很多中定义方式:
class A
class << self
def f
end
end
def self.f
end
def A.f
end
end
def A.f
end
这四种形式,定义的方法,都是 在单例类中保存方法。
对于类来说,结果的形式,就像是其他语言的类的静态方法。
所以直接理解为 类的静态方法,类方法,更加干脆清晰。
只不过 单例方法可以给任何对象定义。
obj = Object.new
def obj.f
end
这样子的定义是成立的。
2.1 extend 与 单例方法
和include对应,有个 extend关键字可以把 module中收集的方法,批量挂载到class上
module B
def f
end
end
class A
extend f
class << self
def f
# 这会覆盖 extend
end
end
end
2.2 覆盖
extend可以批量挂载类方法,class A 内部独立声明的 类方法会覆盖调 extend
2.3 搜索顺序
搜索顺序 instance.singleton_class.ancestors
对比总结下
特点\方法 | 实例方法 | 类方法/单例方法 |
---|---|---|
说明 | 对象的实例的方法 | 可以认为是类的静态方法 |
拓展 | include Module | extend Module |
继承方式 | instance.class.ancestors | instance.singleton_class.ancestors |
覆盖 | 内部定义可覆盖 include | 内部定义可覆盖 extend |
匿名函数
匿名函数在Ruby里面呈现出很多形式
- 块(block)
- Proc类
- lambda
- method
这里细分的有点繁琐,但是总之他们就像匿名函数一样的存在。分别介绍下:
1.块(block)
一般是代码字面书写形式,具体有两种形式
xxx do
end
xxx { }
2.Proc
与块对应的代码对象,有 Proc类,它相当于代码层面上的块,和lambda的区别在于,Proc类内部的return就像代码的return会直接带着环境返回,终止运行。
3.lambda
lambda 是特殊的Proc的实现,他表现的就像一个函数。是真正意义上和其他语言等价的 lambda 函数 —— 匿名函数
4.method
可以把一个对象实例的方法 unbind, 或者 通过 get method 的方式获得 一个类的具体方法,得到的就像一个匿名函数。
而且可以通过 binding 携带上下文执行。
拿JavaScript类比就像 function的call或者 apply
高级部分
Roda中看到的技巧。
include部分、extend部分,他们彼此可以互相覆盖,比如
class A
include B1
include B2
include B3
extend C1
extend C2
extend C3
end
这里,站在实例的角度 B1 B2 B3 等同于拓展 A 实例方法的插件。
站在类角度 C1 C2 C3 是拓展 A类方法的插件。
围绕着覆盖和根据约定使用核心方法,可以制造 —— “插件模式”。
总结
Ruby高度自由的动态性,元编程特性,主要focus在改变语言的构件。
而这些构件中,最最重要的就是 方法本身。
大部分的程序构建都在围绕 块/匿名函数方法、类方法、实例方法 展开。最复杂的部分也就是这样了。
一切万物归一,事情又变的非常简单。
其他讨论
1.为什么要建立那么多方法的概念?
我理解是为了封装
2.是否存在实例的实例方法?
其实大可不必钻牛角尖。
可以理解为,实例方法、类静态方法就是 90%的情况了。
单例类不可见。我们没法在上下文中优雅的为他们建立方法。于是一切就此打住,只有2层需要担心而已。
而复杂的继承模型可以通过 ancestors 相关的自省明确查找顺序。