每个例子都属于不同的情况。
如果您正在编写适用于所有对象的方法,那么您可以打开Object
类,以便所有对象都可以访问它。如果您正在编写适用于所有模块的方法,那么您可以打开Module
。每当你打开一个类来添加方法时,这些方法应该适用于该类的所有实例,仅此而已.
延长Kernel
module 是不同的:人们这样做是为了添加应该可用于每个范围的方法,但实际上并不是通过将它们设为私有来在对象上显式调用的方法。
当你在任何地方之外class
or module
声明,您在该范围内main
对象,并且您定义的方法默认为私有方法Object
。这对于小型或简单的程序来说很好,但您最终会希望使用适当的模块作为命名空间来组织您的方法。
作为关于该主题的最后一点,您始终需要确保您确实希望添加到内置类和模块中的方法可供其他人使用。应用程序中的所有内容,包括外部包含内容因为它们都共享内置函数。
现在应用这个来回答你的问题。因为您正在定义一个为类变量创建访问器的方法,所以您应该将其放在类中Class
因为它适用于所有类别,仅适用于其他类别。最后,您可能只会在类定义中使用它(在class
声明),所以我们应该将其设为私有:
class Class
private
def c_attr_accessor(name)
# ...
end
end
class User
c_attr_accessor :class_variable_name
# ...
end
如果您并不真正在每个类(也许只是几个)中都需要它,那么创建一个“mixin 模块”来扩展需要此功能的每个类:
module ClassVariableAccessor
private
def c_attr_accessor(name)
# ...
end
end
class User
extend ClassVariableAccessor
c_attr_accessor :class_variable_name
# ...
end
请注意,您正在使用Object#extend
to add c_attr_accessor
只针对对象User
(请记住,类是对象;如果您不熟悉 Ruby 元编程,您会经常听到这种说法)。
还有另一种方法可以实现最后一个示例,该方法通过显式扩展其基类来工作Module#included(base_class)
每当模块包含时调用“钩子方法”,并将基类传递给base_class
:
module ClassVariableAccessor
def included(base_class)
base_class.extend ClassMethods
end
module ClassMethods
def c_attr_accessor(name)
# ...
end
end
end
class User
include ClassVariableAccessor
c_attr_accessor :class_variable_name
# ...
end
我推荐最后一个解决方案,因为它是最通用的,并且使用不需要更新的简单界面。我希望这还不算太多!