我什么时候应该使用“类对象",“类模块",“模块内核"?没别的了? [英] When should I use "class Object", "class Module", "module Kernel" and nothing?

查看:64
本文介绍了我什么时候应该使用“类对象",“类模块",“模块内核"?没别的了?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是红宝石元编程的新手,我看到人们在不同的地方进行元编程代码,例如class Objectclass Modulemodule Kernel和"nothing"(即,超出类/模块定义块).

例如:我正在创建一个c_attr_accessor方法来访问类变量,但由于在任何情况下都可以使用,因此我不确定该将代码放在哪里.

如何确定哪个位置更适合放置新的全局代码?

解决方案

每个示例都属于不同的情况.

如果要编写适用于所有对象的方法,则可以打开Object类,以便所有对象都可以访问它.如果要编写适用于所有模块的方法,则打开Module.每当您打开一个类以添加方法时,这些方法应适用于该类的所有实例,而不适用于其他任何实例.

.

扩展Kernel模块的方式有所不同:人们这样做是为了添加应该对每个作用域都可用的方法,但实际上并不能通过将它们设为私有来真正地作为要在对象上显式调用的方法.

当您在任何classmodule语句之外时,您将位于main对象的范围内,并且您定义的方法默认为Object的私有方法.这对于小型或简单的程序都很好,但是您最终将希望使用适当的模块作为命名空间来组织您的方法.

作为对该主题的最后注解,您始终需要确保确实希望添加到内置类和模块中的方法可用于您应用程序中的所有内容,包括外部包含物因为它们都共享内置功能.<​​/p>

现在将其应用于回答您的问题.因为您正在定义一个为类变量创建访问器的方法,所以应将其放在类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仅将c_attr_accessor添加到对象User(请记住类是对象;如果您是Ruby元编程的新手,您会听到很多.)

还有另一种实现最后一个示例的方法,该方法通过显式地扩展其基类通过Module#included(base_class)"hook方法"来实现,只要包含模块,该方法就会被调用,并将基类传递给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

我建议使用最后一种解决方案,因为它是最通用的解决方案,并且使用不需要更新的简单接口.我希望这不是太多!

I'm new to ruby metaprogramming, and I see people metaprogramming code in different places, like class Object, class Module, module Kernel and "nothing" (ie, out of a class/module definition block).

E.g.: I'm creating a c_attr_accessor method to access class variables, and I'm not sure where I must put the code, since it works in any of those cases.

How to decide what place is more appropriate to put a new global code?

解决方案

Each of these examples fall into different cases.

If you are writing methods that apply to all objects, then you open the Object class so all objects can access it. If you are writing methods that apply to all modules, then you open Module. Whenever you open a class to add methods, the methods should apply to all instances of the class and nothing else.

Extending the Kernel module is different: people do this to add methods that should be available to every scope, but not really as methods to be explicitly called on an object, by making them private.

When you are outside of any class or module statement, you are in the scope of the main object, and methods you define default to being private methods of Object. This is fine for small or simple programs, but you will eventually want to use proper modules as namespaces to organize your methods.

As a final note on the subject, you always need to be sure that you really want methods you add to built-in classes and modules to be available to everything in your application, including external inclusions because they all share the built-ins.

Now to apply this to answer your question. Because you are defining a method that creates accessors for class variables, you should put it in the class Class as it applies to all classes and nothing else. Finally, you will likely only use it in class definitions (within a class statement), so we should make it private:

class Class
  private

  def c_attr_accessor(name)
    # ...
  end
end

class User
  c_attr_accessor :class_variable_name

  # ...
end

If you don't really need it in every class (maybe just a few), then create a "mixin module" to extend every class that needs this feature:

module ClassVariableAccessor
  private

  def c_attr_accessor(name)
    # ...
  end
end

class User
  extend ClassVariableAccessor

  c_attr_accessor :class_variable_name

  # ...
end

Note that you are using Object#extend to add c_attr_accessor only to the object User (remember that classes are objects; you will hear that a lot if you are new to Ruby metaprogramming).

There is another way to implement the last example, which works by explicitly extending its base class through the Module#included(base_class) "hook method" called whenever the module included, and the base class is passed to 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

I recommend this last solution because it is the most general and uses a simple interface that should not need to be updated. I hope this is not too much!

这篇关于我什么时候应该使用“类对象",“类模块",“模块内核"?没别的了?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆