Ruby工厂方法调用私有setter

问题描述 投票:1回答:3

我想为一个类创建一个工厂,它将调用一个私有的setter。这可能吗?

这样做:

class Foo
  def self.from_bar(bar)
    f = new bar.foo_id # bar has the id of the foo object I want to make
    f.bar = bar        # but I also wanna store the bar object in foo
    f
  end

  def initialize(id)
  end

  private
  attr_writer :bar

  # lazily load and memoize bar if needed and construction was not
  # made from factory method
  def bar
    @bar ||= ...
  end
end

导致NoMethodError: private method错误。我可以send方法,但我正在寻找一种非hacky方式来做到这一点。

编辑:将attr_accessor更改为attr_writer并添加了memoized reader以显示我的更多意图。

ruby
3个回答
1
投票

只有采用hacky方法才有可能:

class Foo
  def self.from_bar(bar)
    new(bar.foo_id).tap { |f| f.send(:bar=, bar) }
    # or, better:
    new(bar.foo_id).tap { |f| f.instance_variable_set(:@bar, bar) }
  end

  private
  attr_accessor :bar
end

老实说,让attr_accessor私有化有点意义。


1
投票

是的,这是可能的。

Ruby允许您使用send方法从任何地方调用私有方法。

你的工厂看起来像这样:

class FooFactory

  def FooFactory.build(bar)
    foo = Foo.new(generate_id)
    foo.send('bar=', bar)
    foo 
  end 

  private

  def generate_id
    rand(999999)
  end 

end 

然后简单地致电:

FooFactory.build('bar')

请注意,这是工厂的标准模式,发送行也可以在您的代码段中使用。


1
投票

重新阅读这个问题后,我相信这可能就是答案。

  • 您不需要私有的attr_accessor,您只需在initialize方法中设置一个实例变量即可。
  • 似乎存储对象是初始化的一部分,因此不应该是可更改的。

我得出结论,不需要工厂,这可以在初始化方法中完成。

class Foo

  def initialize(id, bar)
    @id = id
    @bar = bar
  end

end

注意:然后您可以使用attr_reader访问栏。哪个将定义bar但不定义bar=

attr_reader :bar
© www.soinside.com 2019 - 2024. All rights reserved.