【问题标题】:Why are setter methods not used in initialization?为什么初始化时不使用 setter 方法?
【发布时间】:2013-12-31 02:15:33
【问题描述】:

最近我一直在阅读“Ruby 中的实用面向对象设计”,我注意到最佳实践之一是使用访问器方法而不是直接获取@instance_variable。例如:

class Foo
  attr_accessor :bar

  def initialize(my_argument)
    @bar = my_argument
  end

  # bad
  # def lorem_ipsum
  #     @bar * 999
  # end

  # good
  def lorem_ipsum
    bar * 999
  end

end

保持事物干燥是有意义的,并且,如果我需要在实际获取其价值之前以某种方式处理@bar。但是,我注意到initialize 方法直接设置了@bar 实例变量的值:

class Foo
  attr_accessor :bar

  def initialize(my_argument)
    @bar = my_argument #<-- why isn't self.bar = my_argument used here?
  end

这是有原因的吗?不应该用setter方法代替直接使用=操作符来设置实例变量的值吗?

【问题讨论】:

    标签: ruby oop


    【解决方案1】:

    你是对的,这样做会更有意义

    class Foo
      attr_accessor :bar
    
      def initialize(my_argument)
        self.bar = my_argument
      end
    end
    

    关于你是否应该尊重对象本身的封装的争论不同,但如果你相信这一点,那么,是的,你应该这样做。

    【讨论】:

    • “如果你相信这一点,那么,是的,你应该这样做。”,并且在你的代码中始终如一地这样做,否则当你未来的自己想知道你为什么不一致时,它会变得混乱.
    【解决方案2】:

    初始化器在初始化时设置值。访问器允许您在对象已经实例化后通过符号访问(读/写)。

    这篇文章可能会帮助您理解: What is attr_accessor in Ruby?

    【讨论】:

    • 你能详细说明一下吗?你是什​​么意思在初始化程序中使用setter?如果初始化程序已经可以访问变量,为什么还需要这样做?
    • 这本书不遗余力地解释了你应该始终使用 setter 和 getter 并且永远不要直接访问实例变量,但它公然忽略了它自己在初始化程序中的建议。但是初始化器只是一个方法,就像任何其他方法一样,所有相同的原因都适用。
    【解决方案3】:

    其实setter可以在initialize中使用,和其他方法一样,但是setter不能在没有receiver的情况下使用。

    我认为您可以使用a_foo.bar=self.bar=,但不能在没有接收器的情况下使用bar=,因为在后一种情况下,bar 将被视为局部变量而不是 setter 方法:

    class Song
      attr_accessor :name
      def initialize(name)
        self.name = name
      end
      def test_setter1(value)
        @name = value
      end
      def test_setter2(value)
        name = value #name is local variable
      end
    end
    
    s = Song.new("Mike")
    p s
    s.test_setter1("John")
    p s
    s.test_setter2("Rosy")
    p s
    

    这会导致:

    #<Song:0x23a50b8 @name="Mike">
    #<Song:0x23a50b8 @name="John">
    #<Song:0x23a50b8 @name="John">
    

    【讨论】:

      【解决方案4】:

      虽然您可以在初始化中使用 setter,如 @uncutstone's answer 所示,但您不能按照代码注释中的建议使用它。

      问题在于 Ruby 会解释:

      bar = my_argument
      

      作为对bar 局部变量的赋值,而不是对bar= 方法的调用。

      这在“Why do Ruby setters need "self." qualification within the class?”中有相当广泛的讨论。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多