【问题标题】:Subclassing core Ruby class such as Hash子类化核心 Ruby 类,例如 Hash
【发布时间】:2012-12-20 13:23:40
【问题描述】:

我需要一个类似于 Hash 的类,但不一定具有所有 Hash 方法。我已经读过,对像 Hash 这样的核心类进行子类化并不是一个好主意。不管这是否属实,做这种事情的最佳做法是什么?

# (a) subclass Hash, add new methods and instance variables
class Book < Hash
   def reindex
     @index = .....
   end
end

# (b) create a new class from scratch, containing a hash, 
#    and define needed methods for the contained hash
class Book
  def initialize(hash)
    @data = hash
  end 
  def []=(k,v)
    @data[k] = v
  end
  # etc....
  def reindex
    @index = ....
  end

# (c) like (b) but using method_missing

# (d) like (b) but using delegation

我意识到 Ruby 有不止一种方法来完成给定任务,但是对于上述哪种方法在相对简单的情况下更可取,有什么通用规则吗?

【问题讨论】:

  • 当你只需要一些方法时,我倾向于组合,用委托。
  • 为什么不能使用Hash?出了什么问题?当您想要添加或更改方法时使用子类化,而不是当您想要删除它们时。
  • @sawa,也许我不清楚。我确实想添加或更改方法。我的示例添加了“重新索引”方法。

标签: ruby hash subclassing duck-typing


【解决方案1】:

如果我绝对不希望类哈希对象具有某些哈希方法,那么我会将对象包装在我自己的类中,并且只公开我希望它具有的方法(您的选项 b)。

如果我希望它通过添加一些行为来保持其真正的哈希行为,我会在模块中将该行为添加到哈希对象本身,而不是修改核心哈希类:

module SpecialHash
  def reindex
    # method def
  end
end

my_hash = {}
my_hash.extend(SpecialHash)
my_hash.reindex #now is defined on my hash

最常见的是,这些选项之一对我有用。

一般来说,我倾向于使用模块来扩展类行为而不是类继承,因为我认为它是一种更简洁、更轻量级的方法。创建一个新类总是让我觉得我正在向我的领域模型添加一个新的“东西”。这很好,这正是您在无数场景中想要做的,但是当您实际上不需要走那么远时,Ruby 的 mixin 功能为您提供了一个非常好的选择。

我处理创建类的主要时间是对象中是否有我想要跟踪的其他状态。如果我的补充不是关于扩展对象的状态,而只是扩展它的行为,那么我几乎总是会从使用模块将该行为混合到该类的现有实例中开始。

此类问题的另一个答案也提出了一些值得牢记的其他要点: ruby inheritance vs mixins

【讨论】:

  • 我同意,但在他的情况下,选项 (b) 更好。他只想公开Hash 的一小部分方法并添加新方法。
  • 实际上,我对一般情况感兴趣,是否要包含所有 Hash 的方法。就像目前发生的那样,让它们都可用是好的。但是,针对 Pete 的解决方案,为什么要将模块添加到对象而不是简单地继承 Hash?让“class Book
  • 抱歉耽搁了,试图扩展我的答案,以便更深入地了解“为什么”我选择在这种情况下所做的选项。希望对您有所帮助!
  • 好的,Pete,这是有道理的,您链接到的讨论很好。对 Hash 进行子类化并添加模块对我来说感觉更自然,所以我可以写“book = Book.new”而不是“book = {}; book.extend(BookBehavior)”,但也许后者更清楚表达正在发生的事情。
猜你喜欢
  • 2013-08-13
  • 2023-03-30
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-13
相关资源
最近更新 更多