Ruby类初始化覆盖模块初始化

时间:2015-06-20 01:51:52

标签: ruby

我正在使用super将参数传递给父initialize方法,默认情况下不会调用该方法。这就是它的样子。 (注意在最后两个参数上使用super

module Pet
  def initialize name, is_pet
    @is_pet = is_pet
    if is_pet
      @name = name
    else
      @name = "Unnamed"
    end
  end
  def pet?
    return @is_pet
  end
  def get_name
    return @name
  end
end

class Dog
  include Pet
  def initialize tricks, name, is_pet
    @tricks = tricks
    super name, is_pet
  end
  def get_tricks
    return @tricks
  end
end

这是我能用它做的事情:

d = Dog.new ["roll", "speak", "play dead"], "Spots", true

d.pet?       #=> true
d.get_tricks #=> ["roll", "speak", "play dead"]
d.get_name   #=> "Spots"

它工作正常,但我只是想知道是否有更好的方法来做到这一点。

2 个答案:

答案 0 :(得分:1)

  • "Unnamed"之类的固定字符串硬编码为@name的值并不是一个好的编程习惯。在这种情况下,您应该分配nil,并在打印时对其进行任何修改。假设你这样做。

  • 然后可以从is_pet是否name推断nil,因此将其作为实例变量是多余的。您只需将!!应用于name即可获得is_pet。因此,你应该摆脱这样的实例变量。

  • 您有get_前缀作为getter方法,但在Ruby中,更好的做法是将实例变量(没有atmark)与getter名称相同。

这会给你:

module Pet
  attr_reader :name
  def initialize name; @name = name end
end

class Dog
  include Pet
  attr_reader :tricks
  def initialize tricks, name
    @tricks = tricks
    super(name)
  end
end

d = Dog.new ["roll", "speak", "play dead"], "Spots"
d.tricks #=> ["roll", "speak", "play dead"]
d.name   #=> "Spots"
!!d.name #=> true (= `is_pet`)

答案 1 :(得分:0)

不要编写调用super的代码进入包含的模块。不要编写期望孩子们打电话给超级的模块。这不是模块的重点。

不要问什么是什么,这是一个很好的面向对象的风格。查找“告诉,不要问”和鸭子打字一般。

如果要提供默认的initialize方法,可能需要继承。但是偶尔会有一些有效的用例来覆盖模块中的初始化。这里惯用的事情是一个钩子方法:

module Pet
  def initialize(options = {})
    @name = options[:name]
    post_initialize(options)
  end

  def post_initialize(options = {})
    # can be overridden in including modules
  end
end

class Dog
  include Pet

  def post_initialize(options = {})
    @tricks = options[:tricks]
  end
end

dog = Dog.new(name: "Fido", tricks: ["play dead", "roll over"])

模块用于在许多不同的事物中包含一些共享行为。很好地将它视为一个形容词,描述你可以用包含它的类做什么。以“-able”结尾的单词(如EnumerableComparable),描述接收类,或“-or”(IteratorInteractor),描述一下上课,是模块的好选择。