programacion privados orientada objetos lenguaje herencia ejemplos con clases clase atributos ruby constructor

privados - programacion con objetos ruby



¿Cómo puedo cambiar el valor de retorno de un constructor de clase en Ruby? (5)

Tengo una clase, Foo. Quiero poder pasar al constructor una instancia Foo, foo y obtener la misma instancia de nuevo.

En otras palabras, quiero que pase esta prueba:

class Foo; end foo = Foo.new bar = Foo.new(foo) assert_equal foo, bar

Alguien sabe cómo puedo hacer eso? Intenté esto:

class Foo def initialize(arg = nil) return arg if arg end end foo = Foo.new bar = Foo.new(foo) assert_equal foo, bar # => fails

pero no funciona.

¿Ayuda?

EDITAR

Porque varias personas me han preguntado mi razón de ser:

Estoy haciendo un análisis rápido de muchos datos (muchos TB) y voy a tener muchas instancias de muchos objetos. Para algunos de estos objetos, no tiene sentido tener dos instancias diferentes con los mismos datos. Por ejemplo, uno de esos objetos es un objeto "ventana" (como en la ventana temporal) que tiene dos propiedades: hora de inicio y hora de finalización. Quiero poder utilizar el constructor de cualquiera de estas formas y recuperar un objeto de ventana:

window = Window.new(time_a, time_b) window = Window.new([time_a, time_b]) window = Window.new(seconds_since_epoch_a, seconds_since_epoch_b) window = Window.new(window_obj) window = Window.new(end => time_b, start => time_a) ...

Algún otro objeto que necesita una ventana puede ser instanciado de esta manera:

obj = SomeObj.new(data => my_data, window => window_arg)

No necesariamente sé qué hay en window_arg, y realmente no me importa, aceptará cualquier argumento único que pueda ser interpretado por el constructor de Windows. En el caso de tener una instancia de Windows, preferiría simplemente usar esa instancia. Pero el trabajo de interpretación parece una preocupación del constructor de Windows. De todos modos, como mencioné, estoy agitando muchos TB de datos y creando muchas instancias de cosas. Si se pasa un objeto de ventana, quiero que sea reconocido como un objeto de ventana y utilizado.


Por definición , los constructores deben devolver un objeto recién creado de la clase de la que son miembros, por lo tanto, no, no debe anular este comportamiento.

Además, en Ruby, las llamadas new se initialize algún lugar dentro de su cuerpo de método, y su valor de retorno se ignora, por lo que de cualquier manera, el valor que devuelve desde la initialize no se devolverá desde new .

Dicho esto, creo que en su caso, es posible que desee crear un método de fábrica que devolverá diferentes objetos Foo función de los argumentos pasados ​​al método de fábrica:

class Foo def self.factory(arg = nil) return arg if arg.kind_of? Foo Foo.new end end foo = Foo.factory bar = Foo.factory(foo) assert_equal foo, bar #passes


initialize es llamado por new que ignora su valor de retorno. Básicamente, el new método predeterminado se ve así (excepto que está implementado en C, no en ruby):

class Class def new(*args, &blk) o = allocate o.send(:initialize, *args, &blk) o end end

Por lo tanto, el objeto recién asignado se devuelve de cualquier manera, sin importar lo que haga en initialize . La única forma de cambiar eso es anular el new método, por ejemplo, como este:

class Foo def self.new(arg=nil) if arg return arg else super end end end

Sin embargo, desaconsejo encarecidamente esto, ya que va en contra de las muchas expectativas que las personas tienen cuando llaman new :

  • La gente espera que new devuelvan un nuevo objeto. Quiero decir que incluso se llama new . Si desea un método que no siempre crea un objeto nuevo, probablemente debería llamarlo de otra manera.
  • Por lo menos la gente espera que Foo.new devuelva un objeto Foo . Tu código devolverá cualquier argumento. Es decir, Foo.new(42) devolvería 42, un Entero, no un objeto Foo . Entonces, si vas a hacer esto, al menos solo debes devolver el objeto dado, si es un objeto Foo .

def Foo.new(arg=nil) arg || super end


No funciona para:

class Some def self.new( str ) SomeMore.new( str ) end end

# the Some is parent of SomeMore class SomeMore < Some def initialize( str ) @str = str end end


Para este caso de uso particular, podría ser mejor utilizar uno de estos enfoques.

Class Foo def self.new(args=nil) @@obj ||= super(args) end end Class Foo def self.new(args) @@obj = super(args) end def self.new @@obj end end

Esto le permite tener solo un objeto que se crea, que puede usarse universalmente, pero devuelve un objeto Foo , haciéndolo más acorde con las expectativas estándar de un new método, como señaló Jacob.