2008-12-10 22 views
14

Estaba leyendo sobre Ruby, y aprendí sobre su patrón de mixins, pero no podía pensar en muchas funcionalidades de mezcla útiles (porque no estoy acostumbrado a pensar de esa manera). Entonces, me preguntaba ¿cuáles serían buenos ejemplos de la útil funcionalidad de Mixin?¿Cuáles son algunos buenos ejemplos de Mixins y/o Rasgos?

Gracias

Editar: Un poco de historia. Vengo de C++ y de otros lenguajes de objetos, pero mi duda es que Ruby dice que no está heredando mixinas, pero sigo viendo mixins como herencia múltiple, así que me temo que estoy tratando de categorizarlos demasiado pronto en mi zona de confort , y realmente no entiendo lo que es mixin.

+2

Es divertido ver las etiquetas [independiente del idioma] y [ruby] sentadas una al lado de la otra como si fueran las mejores amigas =) – Oli

+1

así Ruby provocó la pregunta, pero Mixin y los rasgos se pueden hacer en otros idiomas, como es más un patrón Supongo que –

Respuesta

8

bien el ejemplo habitual Creo que es la persistencia

module Persistence 
    def load sFileName 
      puts "load code to read #{sFileName} contents into my_data" 
    end 
     def save sFileName 
     puts "Uber code to persist #{@my_data} to #{sFileName}" 
    end 

end 

class BrandNewClass 
    include Persistence 
    attr :my_data 

     def data=(someData) 
     @my_data = someData 
    end 
end 

b = BrandNewClass.new 
b.data = "My pwd" 
b.save "MyFile.secret" 
b.load "MyFile.secret" 

Imagínese el módulo está escrito por un ninja de Ruby, que persiste el estado de su clase en un archivo.
Ahora supongamos que escribo una nueva clase, puedo reutilizar la funcionalidad de persistencia mezclándola diciendo include ModuleILike. Incluso puede incluir módulos en tiempo de ejecución. Obtengo los métodos de carga y guardado de forma gratuita simplemente mezclándolo. Estos métodos son exactamente como los que usted mismo escribió para su clase. Código/Comportamiento/Funcionalidad: ¡reutilización sin herencia!

Así que lo que estás haciendo es incluir métodos para la tabla de métodos para tu clase (no literalmente correcta pero cerrada).

+0

Eso parece ser un uso útil. Suena bien de verdad. –

1

Se usa en gran medida como uno podría usar herencia múltiple en C++ o implementar interfaces en Java/C#. No estoy seguro de dónde está tu experiencia, pero si has hecho esas cosas antes, mixins es cómo las harías en Ruby. Es una forma sistematizada de inyectar funcionalidad en clases.

+1

Viniendo de C++, y otros, pero mi duda aquí es que Ruby dice que no está heredando mixinas, pero sigo viendo mixins como herencia múltiple como tú dices, así que me temo que estoy tratando de categorizar ellos demasiado pronto en mi zona de confort, y realmente no entiendo lo que es mixin. –

12

Se suelen utilizar para agregar alguna forma de funcionalidad estándar a una clase, sin tener que redefinirlo todo. Probablemente pueda pensar que se parecen un poco a las interfaces en Java, pero en lugar de simplemente definir una lista de métodos que deben implementarse, muchos de ellos serán realmente implementados al incluir el módulo.

Hay algunos ejemplos en la biblioteca estándar:

Singleton - un módulo que puede ser mezclado en cualquier clase para que sea un producto único. El método de inicialización se hace de forma privada y se agrega un método de instancia, que asegura que solo haya una instancia de esa clase en su aplicación.

Comparable - Si se incluye este módulo en una clase, definiendo el método < =>, que compara la instancia actual con otro objeto y dice que es mayor, es suficiente para proporcionar <, < =, ==,> = ,> y entre? métodos.

Enumerable - Mezclando en este módulo, y que define un cada método, se obtiene el apoyo de todos los otros métodos relacionados, tales como cobro revertido, inyectar, seleccionar y rechazar. Si también tiene el método < =>, también será compatible con sort, min y max.

DataMapper es también un ejemplo interesante de lo que se puede hacer con una declaración de inclusión simple, tomar una clase estándar y agregar la capacidad de persistir en un almacén de datos.

3

En ruby, la razón por la que Mixins no es de herencia múltiple es que la combinación de métodos mixin es una cosa única.Esto no sería un problema tan grande, excepto que los módulos y clases de Ruby están sujetos a modificaciones. Esto significa que si mezclas un módulo a tu clase, entonces agrega un método al módulo, el método no estará disponible para tu clase; donde si lo hicieras en el orden opuesto, lo haría.

Es como pedir un helado. Si obtienes virutas de chocolate y toffee como tu mezcla, y te vas con tu cono, qué tipo de cono de helado tienes no cambiará si alguien agrega rociados multicolores a la bandeja de chocolate en la tienda de helados. Su clase, el cono de helado, no se modifica cuando está el módulo de mixin, el depósito de salpicaduras. La siguiente persona que use ese módulo mixin verá los cambios.

Cuando include un módulo en ruby, llama Module#append_features en ese módulo, que agrega una copia de los métodos de ese módulo al includer una vez.

Herencia múltiple, según tengo entendido, es más como delegación. Si su clase no sabe cómo hacer algo, pregunta a sus padres. En un ambiente de clase abierta, los padres de una clase pueden haber sido modificados después de que se creó la clase.

Es como una relación padre-hijo RL. Es posible que tu madre haya aprendido a hacer malabarismos después de que naciste, pero si alguien te pide que hagas malabarismos y le pides que: te muestre cómo (cópialo cuando lo necesites) o lo haga por ti (delegación pura), entonces ella Podré en ese punto, aunque tú fuiste creado antes de que su habilidad para hacer malabarismos fuera.

Es posible que usted podría modificar un módulo de rubí 'incluir' a actuar más como herencia múltiple mediante la modificación Module#append_features para mantener una lista de includers, y luego actualizarlos mediante la devolución de llamada method_added, pero esto sería un gran cambio desde Ruby estándar, y podría causar problemas importantes al trabajar con otros códigos. Es posible que sea mejor crear un método Module#inherit que llame al include y manejar la delegación también.

En cuanto a un ejemplo del mundo real, Enumerable es impresionante. Si define #each e incluye Enumerable en su clase, eso le da acceso a toda una serie de iteradores, sin tener que codificar todos y cada uno.

+1

Tal vez estoy malinterpretando su punto, o tal vez Ruby ha cambiado desde diciembre de 2008, pero el siguiente código no muestra el comportamiento de "una vez" que usted describe. En particular, tenga en cuenta que la instancia 'Foo' puede invocar el método' fubb' aunque ese método se haya agregado al módulo 'Mixin' * después de que * la clase' Foo' se haya mezclado en el módulo. El código de ejemplo (usando punto y coma para representar saltos de línea): 'módulo Mixin; def bar; pone "Mixin.bar()"; fin; fin; clase Foo; incluye Mixin; fin; módulo Mixin; def fubb; pone "Mixin.fubb()"; fin; fin; f = Foo.new; f.bar; f.fubb'. – FMc

+0

¡Aseado! Supongo que estoy equivocado ahora. Es bueno saberlo, gracias! – rampion

+1

Si cree que está equivocado, ¿puede por favor editar su respuesta y al menos agregar una nota para leer los comentarios? ¡Gracias! – wbyoung

Cuestiones relacionadas