Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby:改进复杂初始化方法_Ruby_Refactoring - Fatal编程技术网

Ruby:改进复杂初始化方法

Ruby:改进复杂初始化方法,ruby,refactoring,Ruby,Refactoring,我有一段Ruby代码,可以归结为: class Foo attr_reader :a, :b, :c def initialize build_a build_b build_c end private def build_a # something complex that eventually results in @a = something end def build_b # something complex th

我有一段Ruby代码,可以归结为:

class Foo
  attr_reader :a, :b, :c
  def initialize
    build_a
    build_b
    build_c
  end

  private

  def build_a
    # something complex that eventually results in @a = something
  end
  def build_b
    # something complex that eventually results in @b = something
  end
  def build_c
    # something complex that eventually results in @c = something
  end
end
initialize
方法中调用
build.*
似乎有点多余。有没有更好的方法写这个?当然,我知道延迟加载模式:

class A
  def a
    @a ||= something_complex
  end
end
但是,我需要这个代码是线程安全的,所以我不能在这里使用这个模式

编辑:我对这段代码的主要关注点是,我希望看到这样一个事实,即
build\u a
应该在初始化后调用,在
build\u a
的定义中编写,而不是在
initialize
方法中编写

require 'active_support/callbacks'

class Foo
  include ActiveSupport::Callbacks
  define_callbacks :initialize

  attr_reader :a, :b, :c

  def initialize
    run_callbacks :initialize do
      # do the rest of initialize
    end
  end

  protected

  def build_a
    # something complex that eventually results in @a = something
  end
  set_callback :initialize, :after, :build_a

  def build_b
    # something complex that eventually results in @b = something
  end
  set_callback :initialize, :after, :build_b

  def build_c
    # something complex that eventually results in @c = something
  end
  set_callback :initialize, :after, :build_c
end
我不是100%确定我喜欢这个解决方案,但它是有效的

编辑:在思考和使用Piotr Kruczek的解决方案后,我采用了以下方法:

class Foo
  def initialize
    protected_methods.grep(/^initialize_/).each do |method|
      send(method)
    end
  end

  protected

  def initialize_a
    # something complex that eventually results in @a = something
  end

  def initialize_b
    # something complex that eventually results in @b = something
  end

  def initialize_c
    # something complex that eventually results in @c = something
  end
end

这些回调将是一个真正的痛苦的驴测试和维护。这个解决方案不是更好吗

class Foo
  attr_reader :a, :b, :c

  def initialize
    # things that belong in initialize
  end

  def self.call # or any other name
    new.build_things
  end

  def build_things
    build_a
    build_b
    build_c
  end
end

唯一的缺点是使用
Foo.call
而不是
Foo.new
。如果你不想让这个类“感觉”像一个服务对象,我会把它包装成一个,比如
FooBuilder
。通过这种方式,您可以避免回调,测试很容易,代码干净易读。如果你想在初始化后
构建东西
,我认为这是最好的方法。

Hmm,我喜欢将这个构建器列表放在另一个方法中的想法,但我不认为它解决了主要问题:调用的方法列表。也许我会尝试实现一个调用所有
build.*
方法或类似方法的循环。