在同一个类的不同对象上设置实例变量

时间:2013-07-21 21:41:19

标签: ruby

假设我有一个名为Person的类,而人有一个名为partner的属性。当我在其中一个partner=对象上调用Person时,我想设置两个对象的@partner实例变量。以下是语法无效的示例:

class Person

  attr_reader :partner

  def partner=(person)

    # reset the old partner instance variable if it exists
    partner.@partner = nil if partner

    # set the partner attributes
    @partner = person
    person.@partner = self
  end
end

5 个答案:

答案 0 :(得分:2)

attr_reader更改为attr_accessor并添加辅助方法:

class Person

  attr_accessor :partner

  def link_partners(person)
    @partner = person
    person.partner = self
  end
end

可见性更新。根据弗雷德里克的建议。这有点冗长,但会阻止合作伙伴直接设置:

class Person
  protected
  attr_writer :partner

  public
  attr_reader :partner

  def link_partners(person)
    @partner = person
    person.partner = self
  end
end

两种实现都是这样的:

p1, p2 = Person.new, Person.new
p1.link_partners(p2) 
# p2.link_partners(p1)

答案 1 :(得分:1)

您可以提供受保护的帮助程序方法,该方法由partner=方法调用以执行实际工作。由于“外人”无法调用,因此您的所有检查和余额都可以在partner=的实施中保留:

class Person
  attr_reader :partner

  def partner=(person)
    @partner.set_partner(nil) if @partner
    set_partner(person)
    person.set_partner(self) if person
  end

  def set_partner(person)
    @partner = person
  end

  protected :set_partner
end

答案 2 :(得分:0)

没关系,我刚发现instance_variable_set

class Person

  attr_reader :partner

  def partner=(person)

    # reset the old partner instance variable if it exists
    partner.instance_variable_set(:@partner, nil) if partner

    # set the partner attributes
    @partner = person
    person.instance_variable_set(:@partner, self)
  end
end

答案 3 :(得分:0)

理论上,你可以这样做:

def partner=(person)
  @partner = person
  person.instance_variable_set(:@partner, self)
end

但是,我认为这是神奇的。 (这不是一件好事。)而是将attr_reader变为attr_accessor并编写另一种方法,将两个person s'partner彼此设置。< / p>

答案 4 :(得分:0)

这将解决您的递归设置问题并且看起来比您的解决方案更好:

class Partner
  attr_reader :partner
  def set_partner(person, recursive = true)
    # reset previous partner
    @partner.set_partner(nil, false) if recursive && @partner

    # set new partner
    @partner = person
    @partner.set_partner(self, false) if recursive
  end
  alias_method :partner=, :set_partner
end