在调用#initialize之前,如何对类实例执行操作?

时间:2015-10-12 10:04:56

标签: ruby

我正在编写一个类,其中实例变量具有,以便在初始化期间进行设置,或者该类无法正常工作。该类设计为大量子类,我不希望所有子类必须在super重载中调用initialize,所以我想在之前设置实例变量 调用初始化函数。

在调用Class#new函数之前,是否可以通过重载initialize或类似的东西来进行一些自定义实例初始化

像:

class Foo < MySuperClass
  def initialize
    # @foo is already set to 123 because of the magic in MySuperClass
    assert @foo == 123
  end
end

3 个答案:

答案 0 :(得分:3)

您可以使用模板方法模式,而不是依赖于子类中的#initialize,如下所示:

class Parent
  def initialize
    @foo = 123
    my_initialize
  end

  # Concrete classes must override
  def my_initialize
    raise NoMethodError
  end
end

class Child < Parent
  def my_initialize
    puts @foo
  end
end

另一种方法,如果你不想使用模板方法,那么prepend是一个包含初始化逻辑的模块(在Ruby 2中添加了prepend):

class Parent  
  def self.inherited(class_name)
    class_name.prepend Initializer
  end

  module Initializer
    def initialize
      # Your initialization code
      @foo = 123

      # Call your child class's initialize
      super
    end
  end
end

class Child < Parent
  def initialize
    puts @foo
  end
end

以下是关于Module#prepend:http://gshutler.com/2013/04/ruby-2-module-prepend/

的优秀入门读物

答案 1 :(得分:0)

延迟初始化

class MySuperClass
  protected
  def foo
    @foo ||= 123
  end
end

class Foo < MySuperClass
  def initialize
    assert foo == 123
  end
end

答案 2 :(得分:0)

我在this forum thread找到了一个有趣的方式:

class MySuperClass
  def self.new(*args, &block)
    instance = allocate()

    # Pre-initialize
    instance.instance_variable_set(:@foo, 123)

    instance.send(:initialize, *args, &block)

    return instance
  end
end

这会覆盖默认的Class.new方法并手动创建实例。这意味着我可以在调用initialize之前跳转并设置实例变量。