在阅读开源的 Ruby 代码和编写可维护性的代码经常遇到这两者的使用,那么他们两者的共同点和区别是什么呢?
module_function
Ruby 的 module 是 method 和 constants 的集合。module 中的method 又可分为 instance method 和 module method, 当一个 module 被 include 进一个 class ,那么 module 中的 method (注:没有被 module_function 标记的 method)就是 class 中的 instance method, instance method 需要所在的 class 被实例化之后才能被调用;被 module_function 标记的 method(不管该 method 是 public 或者 private)就是 module method 且 instance method 也会变成 private method,对于被 include 所在的 class 来说是 private method,object.module_name 会出错。module method 都能被 module_name.method_name 调用,没有被 module_function 标记的 public method 不能被 module_name.method_name 调用。
module 中的 module_function 会把 module 中的 method 变成 module method 且对于被 include 所在的 class 来说,module method 在 module 中是 private method 故 module_name.module_method 能调用,而不能被 object.module_name 调用。
module 中的 public method 对于被 include 所在的 class 来说是 instance method,故 object.public_method_in_module 能调用。如果想要非 module method 能够被 module 调用(module_name.not_module_method) ,需要引入 extend self (下文会讨论 extend self)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
# test.rb module MyModule def public_meth p "a public method, if the module is included to a class , can be call as object.public_meth" end def module_method p "a module method,can be called as module_name.module_method. but can not be call as object.module_method" end private def private_method_to_module_function p "a private_method, but can be call as module_name.module_method, because it was assigned to module_function" end def private_method p "I am a private method" end module_function :module_method , :private_method_to_module_function end MyModule.module_method MyModule.private_method_to_module_function begin MyModule.public_meth rescue p "public method can not be called by module_name.public_meth" end begin MyModule.private_method rescue NoMethodError p "private method can not be called by module_name.module_method" end class MyClass include MyModule end obj = MyClass. new obj.public_meth begin obj.private_method rescue NoMethodError p "private method in module can not be call by object.method_name" end begin obj.module_method rescue NoMethodError p "module method can not be called by object.method_name, for object, module method is private instance method" end #调用 ruby test.rb "a module method,can be called as module_name.module_method. but can not be call as object.module_method" "a private_method, but can be call as module_name.module_method, because it was assigned to module_function" "public method can not be called by module_name.public_meth" "private method can not be called by module_name.module_method" "a public method, if the module is included to a class , can be call as object.public_meth" "private method in module can not be call by object.method_name" "module method can not be called by object.method_name, for object, module method is private instance method" |
总结就是
•The method will be copied to class' singleton class
•The instance method's visibility will become private
extend self
Include is for adding methods to an instance of a class and extend is for adding class methods
extend 本质是给 class 或者 module 添加 class method
extend self 让 module 中的 instance method 能够被 module_name.instance_method 调用,保留 module 中原本 method 的 public 或 private 属性,但又不像 module_function 一样把被标记的 method 变成 private 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#!/usr/bin/env ruby # encoding: utf-8 # test_extend.rb module MyModule extend self def public_meth p "a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class" private_method end private def private_method p "a private method, can be call in module internal" end end class MyClass include MyModule end MyModule.public_meth begin MyModule.private_method rescue NoMethodError p "private method in extend self module can not be called module_name.private_method" end obj = MyClass. new obj.public_meth begin obj.private_method rescue NoMethodError p "private method can not be called by object.private_method" end # 调用 ruby test_extend.rb "a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class" "a private method, can be call in module internal" "private method in extend self module can not be called module_name.private_method" "a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class" "a private method, can be call in module internal" "private method can not be called by object.private_method" |
总结就是:
•No method copying involved
•No changes to method visibility
总结
module_function 改变 module 内 原来 method 的 public/private 属性并把改 method 变成 module method ,能够被 module_name.module_method 调用。
extend self 就是在 module 自继承,不改变 module 中 method 的 public/private 属性,能够被 module_name.public_method