对核心Ruby类(如Hash)进行子类化

对核心Ruby类(如Hash)进行子类化,ruby,hash,subclassing,duck-typing,Ruby,Hash,Subclassing,Duck Typing,我需要一个类似于散列的类,尽管不一定包含所有的散列方法。我读到过,像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, con

我需要一个类似于散列的类,尽管不一定包含所有的散列方法。我读到过,像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
#(a)子类Hash,添加新方法和实例变量
类目

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

如果我绝对不希望类似散列的对象有某些散列方法,然后我将对象包装在我自己的类中,只公开我希望它拥有的方法(您的选项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功能在您实际上不需要走那么远的时候为您提供了一个非常好的选择

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

这类问题的另一个答案也提出了一些值得记住的其他问题:

当您只需要一些方法时,我倾向于使用委托的合成方法。为什么您不能使用
散列
?出了什么问题?子类化是在您想要添加或更改方法时使用的,而不是在您想要删除方法时使用的。@sawa,也许我不清楚。我确实想添加或更改方法。我的例子添加了“reindex”方法。我同意,但在他的例子中,选项(b)更好。他只想公开一小部分Hash的方法并添加新的方法。实际上,我对一般情况感兴趣,不管我是否想包含所有Hash的方法。正如目前所发生的那样,让他们都可以使用是很好的。但是,针对Pete的解决方案,为什么要将模块添加到对象中,而不是简单地将哈希子类化?让“classbook