ruby 的 include 和 extend
一个mudule或class可以通过include方法加入另一个module的属性和方法。Module.include(aModule),默认的动作是:
When this module is included in another, Ruby calls append_features in this module, passing it the receiving module in aModule. Ruby's default implementation is to add the constants, methods, and module variables of this module to aModule if this module has not already been added to aModule or one of its ancestors. See also Module#include on page 345.
Mixins---Including Modules
用法:
class|module name
include expr
end
A module may be included within the definition of another module or class using the include method. The module or class definition containing the include gains access to the constants, class variables, and instance methods of the module it includes.
If a module is included within a class definition, the module's constants, class variables, and instance methods are effectively bundled into an anonymous (and inaccessible) superclass for that class. In particular, objects of the class will respond to messages sent to the module's instance methods.
A module may also be included at the top level, in which case the module's constants, class variables, and instance methods become available at the top level.
关于extend:
Module#included is a callback method that is automatically called during the inclusion of a module into a class. The default included implementation is an empty method. In the example, MyLib overrides it to extend the class that's including the MyLib module with the contents of the MyLib::ClassMethods submodule.
The Object#extend method takes a Module object as a parameter. It mixes all the methods defined in the module into the receiving object. Since classes are themselves objects, and the singleton methods of a Class object are just its class methods, calling extend on a class object fills it up with new class methods.
extend obj.extend( [ aModule ]+ ) -> obj
Adds to obj the instance methods from each module given as a parameter.
module Mod
def hello
"Hello from Mod.\n"
end
end
class Klass
def hello
"Hello from Klass.\n"
end
end
k = Klass.new
k.hello » "Hello from Klass.\n"
k.extend(Mod) » #<Klass:0x401b3a04>
k.hello » "Hello from Mod.\n"
可见,extend是将参数中的module中的方法和属性混入到目标对象中。而include是作为目标对象的anonymous superclass的方式。这还是有差异的。 仔细理解一下extend的 :“Adds to obj the instance methods from each module given as a parameter”
extend可以将module混入到一个instance 对象,也可以混入到一个class对象中。
比如instance对象:[code]module Mod
def hello
"Hello from Mod.\n"
end
end
class Klass
def hello
"Hello from Klass.\n"
end
end
k = Klass.new
k.hello » "Hello from Klass.\n"
k.extend(Mod) » #<Klass:0x401b3a04>
k.hello » "Hello from Mod.\n"
[/code]现在是extend class 对象:[code]module Mod
def hello
"Hello from Mod.\n"
end
end
class Klass
def hello
"Hello from Klass.\n"
end
extend Mod
end
k = Klass.new
puts k.hello
puts Klass.hello[/code] 一些callbacks
When a class extends a module the module’s self.extended method will be invoked。当一个class extend一个module时,module的self.extended(c)会被自动执行。其中m就是被extend的对象。
同样:当被include时。self.included(c)会被执行。 下面来看一个来自ruby cookbook的一个实例。[code] require 'memcache'
module GetSetMemcaching
SERVER = 'localhost:11211'
def self::extended(mod)
mod.module_eval do
alias_method :__uncached_get, :get
remove_method :get
def get(key)
puts "Cached get of #{key.inspect}"
get_cache()[key] ||= __uncached_get(key)
end
def get_cache
puts "Fetching cache object for #{SERVER}"
@cache ||= MemCache.new(SERVER)
end
end
super
end
def self::included(mod)
mod.extend(self)
super
end
end
MyDataLayer.extend(GetSetMemcaching)
[/code]下面来说说作者为什么这样写。
前面说道include和extend都是将module中的属性、静态属性、和实例方法加到目标对象中。但是include是通过类似继承的方法,extend是通过添加(包括覆盖)的方法。
在上面的例子中,作者在GetSetMemcaching中定义了两个模块方法(静态方法),这两个方法不会被include或者exend到目标对象中去。所以按照默认的include和extend,这个GetSetMemcaching不会给目标对象引入新的东西。但是这里面的self.extended和self.included都是ruby语言中的callback函数,在module被include或者extend的时候会被呼叫。
这个例子中,作者是想完全由自己来控制include和extend的行为,所以不管是include或者extend,其实际效能是一样的,最终都是执行extended(mod)的内容。
页:
[1]
