抽象这种模式的最佳方法是什么?
class MyClass attr_accessor :foo,:bar def initialize(foo,bar) @foo,@bar = foo,bar end end
解决方法
这个问题的解决方案已经(部分)
exists,但是如果你想在你的类中使用更多的声明性方法,那么下面的代码应该是可行的.
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
你现在可以做到:
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
这个解决方案的一些特点:
>使用initialize_with指定构造函数属性
>可以使用initialize来进行自定义初始化
>可能在初始化时调用super
>初始化的参数是由initialize_with指定的属性未被消耗的参数
>轻松地提取到模块中
>使用initialize_with指定的构造方法属性是继承的,但是在子类上定义新集合将删除父属性
>动态解决方案可能有性能下降
如果要创建具有绝对最低性能开销的解决方案,将大多数功能重构为字符串并不难,可以在定义初始化程序时对其进行评估.我没有将差异作为基准.
注意:我发现黑客新作比黑客入侵初始化更好.如果使用元编程定义initialize,则可能会得到一个方法,您将一个块传递给initialize_with作为替代初始化程序,并且不可能在块中使用super.