为什么我们定义`#initialize`而不是`:: new`

时间:2013-01-14 22:30:51

标签: ruby design-patterns

在Ruby中,在创建新类时,我们将定义构造函数方法,如下所示:

class Thing
  def initialize
     do_stuff
  end
end

但是,当实际创建对象的实例时,我们发现自己没有在实例上调用initialize而在类上调用new

在这种情况下,我们为什么不改为定义::new

class Thing
   def self.new
     do_stuff
   end
end

::new没有定义的场景是initalize吗?这两者有什么不同吗?定义::new会有效吗?或者只是def initializedef self.new更短(不是)?

我认为必须有充分的理由来弥补这种差异。

3 个答案:

答案 0 :(得分:11)

New为新对象分配空间并创建它。然后,它调用Objects initialize方法,使用分配的内存创建一个新的Object。通常,您要自定义的唯一部分是实际创建,并且很乐意将后台内存分配留给Object.new方法,因此您编写了一个初始化方法。引擎盖下的新功能看起来像这样(C中除外):

 class Object
    def self.new(*args, &block)
        object = allocate
        object.send(:initialize, *args, &block)
        return object
    end
 end

因此,当您调用Object.new时,实际发生的是:

1)分配内存 2)调用对象初始化方法。

答案 1 :(得分:5)

提供对实例变量的访问。

实例变量(例如@value)只能从实例访问,但不能从类方法中访问。这与Java之类的语言不同,其中私有实例变量具有类而不是实例范围,因此可以从静态构造函数访问。

class Thing
  def initialize
     @value = 42
  end
end

class Thing
  def self.new
    # no way to set the value of @value !!!!!!!!
  end
end

对于那些对Ruby历史感兴趣的人,具有实例私有实例变量的对象模型可以追溯到Smalltalk。你可以在现代的Smalltalk方言中找到相同的模式,例如PharonewObject中实现,以调用self initialize,以便子类可以轻松初始化实例变量。

答案 2 :(得分:3)

  • 详细说明亚伯拉罕的观点,实际上是扭转了包裹关系。如果您将allocate作为基元并且通常定义new,那么您将始终必须执行常见操作,例如调用allocate并在最后返回对象,这对于做。通过使用newinitialize,前者将包装后者,因此您只需要定义包装内容,而不是包装器。
  • new是一个类方法,所以当你定义它时,默认情况下你没有访问实例方法和实例变量,你需要依赖访问器。另一方面,initialize是一个实例方法,因此使用实例变量和实例方法会更容易。