我有一段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
在build_*
方法中调用initialize
似乎有点多余。有没有更好的方法来写这个?我当然知道延迟加载模式:
class A
def a
@a ||= something_complex
end
end
但是,我需要这个代码是线程安全的,所以我不能在这里使用该模式。
编辑:我对此代码的主要关注是,我希望看到build_a
应在初始化后调用,在build_a
而不是{{1}的定义中编写的事实方法。
答案 0 :(得分:1)
现在我一起去了
#bg {
background-image: url('small.jpg');
}
@media (min-width: 768px) {
#bg {
background-image: url('big.jpg');
}
}
我不是100%确定我喜欢这个解决方案,但它确实有效。
编辑:经过一番思考和玩弄Piotr Kruczek的解决方案,我接受了这个:
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
答案 1 :(得分:1)
这些回调将是测试和维护的真正痛苦。这个解决方案不会更好吗?:
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
。这样就可以避免回调,测试很简单,代码清晰可读。如果你想在初始化后build_things
,我认为这是最好的方法。