Eigenclass Practice

前面我们说过 attr_accessor() 方法,它能为任何 对象 创建属性:

  class MyClass
    attr_accessor :a
  end

  obj = MyClass.new
  obj.a = 2
  obj.a          #=> 2

但是,如果想给类创建属性呢?你可能会试图重新打开 Class 并且在那里定义属性:

  class MyClass;end

  class Class
    attr_accessor :b
  end

  MyClass.b = 42
  MyClass.b       #=> 42

但这样做会给所有的类都添加这个属性。如果希望添加专属于 MyClass 的属性,就需要使用另一种技术—-在它的 eigenclass 中定义该属性:

  class MyClass
    class << self
      attr_accessor :c
    end
  end

  MyClass.c = 'It works!'
  MyClass.c                #=> "It works!"

一个属性实际上只是一对方法,如果在 eigenclass 中定义这些方法,则它们实际上会成为类方法。

当类包含模块时,能够扩展该类的实例方法。如果想扩展该类的类方法,则应该在它的 eigenclass 中包含模块:

  module MyModule
    def my_method; 'hello'; end
  end

  class MyClass
    class << self
      include MyModule
    end
  end

  MyClass.my_method       #=> "hello"

my_method() 方法是 MyClass 的 eigenclass 的一个实例方法,这样,my_method() 也是 MyClass 的一个类方法。这种技术称为 类扩展

类方法其实是单件方法的特例,因此可以把这种技巧推广到任意对象。一般情况下,这种技术称为 对象扩展

  module MyModule
    def my_method; 'hello'; end
  end

  obj = Object.new
  class << obj
    include MyModule
  end

  obj.my_method           #=> "hello"
  obj.singleton_methods   #=> [:my_method]

类扩展对象扩展 的应用非常普遍,因此 Ruby 为它们专门提供了一个叫做 Object#extend() 的方法:

  module MyModule
    def my_method; 'hello'; end
  end

  obj = Object.new
  obj.extend MyModule
  obj.my_method          #=> "hello"

  class MyClass
    extend MyModule
  end
  MyClass.my_method      #=> "hello"