6

在 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 initialize比 短(不)def self.new

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

4

3 回答 3

13

New 为新对象分配空间并创建它。然后它调用 Objects 的初始化方法来使用分配的内存创建一个新的 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) 调用对象初始化方法。

于 2013-01-14T22:39:08.060 回答
7

提供对实例变量的访问。

实例变量,例如@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 方言中发现相同的模式,例如Pharonew被实现Object为调用self initialize,以便子类可以轻松地初始化实例变量。

于 2013-01-14T23:26:02.840 回答
4
  • 详细说明亚伯拉罕的观点,实际上就是颠倒了包裹关系。如果你有allocate一个原始的并且通常是定义的new,那么你总是必须做一些常见的事情,比如allocate最后调用和返回对象,这是一件多余的事情。通过拥有newand initialize,前者将包装后者,因此您只需要定义包装的内容,而不是包装器。
  • new是一个类方法,所以当你定义它时,默认情况下你没有访问实例方法和实例变量的权限,你需要依赖访问器。另一方面,initialize它是一个实例方法,因此使用实例变量和实例方法会更容易。
于 2013-01-14T23:12:39.103 回答