抽象初始化属性的最佳方法

Yeh*_*atz 12 ruby abstraction

抽象这种模式的最佳方法是什么:

class MyClass
  attr_accessor :foo, :bar

  def initialize(foo, bar)
    @foo, @bar = foo, bar
  end
end
Run Code Online (Sandbox Code Playgroud)

一个好的解决方案应该考虑超类,并且能够处理仍然能够使用初始化程序来执行更多操作.在您的解决方案中不牺牲性能的额外要点.

mol*_*olf 7

已经(部分)存在该问题的解决方案,但如果您希望在类中使用更具说明性的方法,则以下内容应该有效.

class Class
  def initialize_with(*attrs, &block)
    attrs.each do |attr|
      attr_accessor attr
    end
    (class << self; self; end).send :define_method, :new do |*args|
      obj = allocate
      init_args, surplus_args = args[0...attrs.size], args[attrs.size..-1]
      attrs.zip(init_args) do |attr, arg|
        obj.instance_variable_set "@#{attr}", arg
      end
      obj.send :initialize, *surplus_args
      obj
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

你现在可以这样做:

class MyClass < ParentClass
  initialize_with :foo, :bar
  def initialize(baz)
    @initialized = true
    super(baz) # pass any arguments to initializer of superclass
  end
end
my_obj = MyClass.new "foo", "bar", "baz"
my_obj.foo #=> "foo"
my_obj.bar #=> "bar"
my_obj.instance_variable_get(:@initialized) #=> true
Run Code Online (Sandbox Code Playgroud)

该解决方案的一些特征:

  • 使用指定构造函数属性 initialize_with
  • 可选择用于initialize进行自定义初始化
  • 可以调用superinitialize
  • 参数initialize是指定的属性未使用的参数initialize_with
  • 轻松提取到模块中
  • 指定的构造函数属性initialize_with是继承的,但在子类上定义新集将删除父属性
  • 动态解决方案可能会受到影响

如果要创建具有绝对最小性能开销的解决方案,将大多数功能重构为字符串并不困难,可以在eval定义初始化程序时对其进行编辑.我没有确定差异的基准.

注意:我发现黑客攻击new比黑客攻击更好initialize.如果initialize使用元编程定义,则可能会出现将块传递initialize_with给替代初始值设定项的情况,并且无法super在块中使用.