ruby - tag - ¿Cuáles son algunos buenos ejemplos de Mixins y/o Rasgos?
qué es un meta html (4)
Bueno, el ejemplo habitual, creo que es 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"
Imagine que el módulo está escrito por un ninja de Ruby, que persiste en 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!
Entonces, lo que estás haciendo es incluir métodos para la tabla de métodos para tu clase (no literalmente correcta pero cercana).
Estaba leyendo sobre Ruby, y aprendí sobre su patrón de mixinas, 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?
Gracias
Edición: un poco de fondo. 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.
En ruby, la razón por la que Mixins no es de herencia múltiple es que combinar 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 cono de 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 basura 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 a Module#append_features
en ese módulo, que agrega una copia de los métodos de ese módulo al includer una vez.
La herencia múltiple, según tengo entendido, se parece más a la 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 pueda modificar un módulo de ruby ''include'' para que Module#append_features
más como herencia múltiple modificando Module#append_features
para mantener una lista de includers, y luego actualizarlos mediante callback method_added
, pero esto representaría un gran cambio respecto al estándar Ruby. y podría causar problemas importantes al trabajar con otros códigos. Es posible que sea mejor crear un método de Module#inherit
que también llame a la delegación include
y dirigida.
En cuanto a un ejemplo del mundo real, Enumerable
es increíble. 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.
Generalmente se usan 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 se implementarán al incluir el módulo.
Hay algunos ejemplos en la biblioteca estándar:
Singleton: un módulo que se puede combinar en cualquier clase para convertirlo en singleton. El método de inicialización se hace de forma privada y se agrega un método de instancia, que garantiza que solo haya una instancia de esa clase en su aplicación.
Comparable: si incluye este módulo en una clase, definir el método <=>, que compara la instancia actual con otro objeto y dice cuál es mayor, es suficiente para proporcionar <, <=, ==,> =,> y ¿Entre? métodos.
Enumerable: al mezclar en este módulo y definir cada método, obtiene soporte para todos los demás métodos relacionados, como recopilar, 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 instrucción de inclusión simple, tomar una clase estándar y agregar la capacidad de persistir en un almacén de datos.
Se usa ampliamente ya que uno puede 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.