From: Stefano Crocco Date: 2007-01-25T02:31:50+09:00 Subject: Re: Can Ruby do the Objective-C/Cocoa style alloc/init pattern? Alle 10:50, mercoled� 24 gennaio 2007, Greg Hurrell ha scritto: > In Objective-C/Cocoa objects normally come to life in the following > way: > > instance = [[Class alloc] init]; > > The "Class" is sent an "alloc" message (memory is allocated and a new > instance is actually created) and then the new instance is sent an > "init" message (allowing the object to prepare itself for use). > > This pattern allows you do some cool dynamic things. For example, in > your "init" method you can actually return a different object than the > one that was allocated. This is pretty cool because it means you can > return objects of different classes depending on the parameters that > are passed to your "init" method. > > Is there any way to do something similar in Ruby? Sending "new" to a > class in Ruby is kind of like doing an "alloc" in Objective-C/Cocoa, > and the Ruby "initialize" method is similar to the Objective-C/Cocoa > "init" method; but unlike Objective-C/Cocoa it really doesn't matter > what you return from your "initialize" method so there doesn't seem to > be any way to return an object of a different class. > > I can think of ways to fake this pattern but I am not sure if they're > the best idea. For example, I could add a new class method (could even > call it "alloc" if I wanted) and a new instance method "init" and > basically fake the Cocoa/Objective-C behaviour; but I don't want to > deform Ruby until it looks like Objective-C, I'd rather find a means of > implementing this pattern the "Ruby Way". > > What do the experienced Rubyists have to say? > > Cheers, > Greg I'm not an experienced rubyst, but I think you need to overload new, not initialize: class A def initialize puts "initialize for class A" end end class B def initialize arg puts "initialize for class B. arg is #{arg}" end end class C def initialize puts "initialize for class C" end end class D def self.new cls, *args const_get(cls).new *args end end a=D.new 'A' => initialize for class A b=D.new 'B', 1 => initialize for class A c=D.new 'C' => initialize for class A puts a.class => A puts b.class => B puts c.class => C At any rate, I'm not sure this is the best way, at least if class D should never be instantiated. In this case, I'd go with a module: module Mod class A end class B end class C end def Mod.create cls, *args const_get(cls).new *args end end puts Mod.create('A').class =>A Stefano