动态派发与动态方法

动态派发(Dynamic Dispatch)用的方法是Object#send;
动态方法(Dynamic Method)用的方法是Module#define_method.

动态派发

例子:

1
2
3
4
5
6
7
8
9
class Myclass
def my_method(my_arg)
my_arg*2
end
end

obj = Myclass.new
obj.my_method(3) #=>6 正常的情况
obj.send(:my_method, 3) #=>6 使用动态派发

我们还可以举一个例子

1
2
3
1+1 #=>2
#应为1也是一个对象,+不是关键字而是一个方法,所以我们也可以这样使用,如下
1.send(:+, 1) #=>2

说明一下这个方法的参数,第一个参数是你要发送消息给对象的消息,即方法;剩下的参数(包括代码块)会直接传递给调用的方法。
其实看了《元》这书还没有很好的消化,暂时对这种方法的理解就是:在代码运行的时候去动态的调用一个方法。(可以通过参数,去动态调用这个方法)

比如说我们有

```get_mouse_info```这两个实例方法,我们可以通过参数来调用这两个方法,如
1
```
def xxx(name)
  info = @data_source.send "get_#{name}_info", @id
....
end

然后我们只要

1
2
xxx(:cpu) #在xxx方法中调用get_cpu_info方法
xxx(:mouse) #在xxx方法中调用get_mouse_info方法

动态方法

例子:

1
2
3
4
5
6
7
8
class Myclass
define_method :my_method do |my_arg|
my_arg * 3
end
end

obj = Myclass.new
obj.my_method(2) #=> 6

注意:define_method 在类中执行,那么my_method是实例方法
动态方法,我的理解是:可以通过参数来动态的创建方法。我们来看这个例子(例子中除了动态方法还用到了动态派发)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Computer
...
def self.define_computer(name)
define_method(name) {
info = @data_source.send "get_#{name}_info", @id
...
}
end

define_computer :mouse
define_computer :cpu
define_computer :keyboard
end

我们先来看看self.define_computer这个方法,self现在是指的是Computer这个类,所以这是一个类方法,而define_method是执行与类中,所以定义的(name)参数所对应的方法是实例方法。我们现在看看下面的代码,

:mouse```执行调用define_computer这个类方法,并将mouse这个参数传给了它,然后在这个类方法中又将这个参数传给了define_method这个方法,于是动态的创建了一个叫做mouse的实例方法,这个实例方法完整的写出来应该是这样的:
1
```
def mouse
   info = @data_source.send "get_#{name}_info", @id
   ...
end

同理

1
2
define_computer :cpu
define_computer :keyboard

分别调用dfine_computer这个类方法,然后动态的创建了cpu和keyboard这两个实例方法。

特别注意:define_method在类中执行,生成的动态方法是一个实例方法。

说明:这两个方法的介绍在《元》中是用来解决代码重复的作用的,下面还有一种方法来解决代码重复的问题(用到了动态代理和白板技术)