¿Herencia vs mixins en lenguajes dinámicos?

19

¿Cuándo debería preferir patrones de herencia sobre mixins en lenguajes dinámicos?

Por mixins, me refiero a una verdadera mezcla, como al insertar funciones y miembros de datos en un objeto en tiempo de ejecución.

¿Cuándo usaría, por ejemplo, la herencia de prototipos en lugar de mixins? Para ilustrar más claramente lo que quiero decir con mixin, algunos pseudocódigo:

asCircle(obj) {
  obj.radius = 0
  obj.area = function() {
    return this.radius * this.radius * 3.14
  }

myObject = {}
asCircle(myObject)
myObject.area() // -> 0
Magnus Wolffelt
fuente
2
Los mixins se parecen más a aspectos transversales que a la herencia directa. Eso probablemente definirá algunos casos de uso para usted.
cenizas999 05 de
1
Composición, cualquiera :)
OnesimusUnbound

Respuestas:

14

La herencia prototípica es simple. Tiene una sola ventaja sobre los mixins.

Es que es un enlace en vivo. si cambia el prototipo, todo lo que hereda se cambia.

Ejemplo usando pd

var Circle = {
  constructor: function _constructor() {
    this.radius = 0;
    return this;
  },
  area: function _area() {
    return this.radius * this.radius * Circle.PI
  },
  PI: 3.14
};

var mixedIn = pd.extend({}, Circle).constructor();
var inherited = pd.make(Circle, {}).constructor();

Circle.perimeter = perimeter;

inherited.perimeter(); // wins
mixedIn.perimeter(); // fails

function perimeter() {
  return 2 * this.radius;
}

Básicamente, si desea que los cambios en el círculo de "interfaz" se reflejen en tiempo de ejecución a todos los objetos que "usan" su funcionalidad, entonces herede de ella.

Si no desea que se reflejen los cambios, mézclelos.

Tenga en cuenta que los mixins también tienen más propósito que eso. Las mixinas son su mecanismo para la "herencia" múltiple.

Si desea que un objeto implemente múltiples "interfaces", entonces tendrá que mezclar algunas. La que use para la herencia prototípica es la que desea que reflejen los cambios en el tiempo de ejecución, las otras se mezclarán.

Raynos
fuente
12

Mi sentido del caballo me dice esto:

  • Si algo es útil en varios objetos o jerarquías de clase, conviértalo en un mixin
  • Si algo solo es útil en una única jerarquía, use la herencia

Notas Relacionadas:

  • La palabra "útil" debe tomarse metafóricamente
  • Para aquellos idiomas que no tienen herencia múltiple, los mixins son una buena alternativa
  • PHP 5.4 presenta rasgos que tienen bondad de ambos mixins y múltiples mundos de herencia
codificador de árboles
fuente
+1, mi ejemplo favorito de "algo útil en varios objetos o jerarquías de clase" en Ruby es Módulo enumerable
David
1
Yo diría que la herencia múltiple puede ser una alternativa (no tan buena) a las mixinas.
Simon Bergot
@Simon Yo diría que los mixins pueden ser una alternativa (no tan buena) a la herencia múltiple;)
Raynos
Mi sentido del caballo también me dijo esto. :)
theringostarrs
9

Use la prueba "Is-a".

La herencia se limita al caso cuando puede decir "Subclase ES UNA Superclase". Son el mismo tipo de cosas. "El queso es un producto lácteo".

Los mixins son para todo lo demás. "El queso se puede usar en un sándwich". El queso no es un sándwich, pero participa en el emparedado.

PD. Esto no tiene nada que ver con lenguajes dinámicos. Cualquier lenguaje de herencia múltiple con compilación estática (es decir, C ++) tiene el mismo punto de decisión.

S.Lott
fuente
Definitivamente + 1- los idiomas estáticos también tienen mixins.
DeadMG
Bien, los mixins se pueden hacer en muchos idiomas, esta no era mi pregunta. Los lenguajes dinámicos tienen ciertas propiedades que pueden o no hacer que los mixins sean diferentes y / o más interesantes en dichos lenguajes - Raynos señaló un aspecto. Además, no señala ninguna razón específica por la que uno debería usar el concepto IS A sobre el concepto mixin.
Magnus Wolffelt
@MagnusWolffelt: Son el mismo tipo de cosas. "El queso es un producto lácteo". Esa es la regla para IS-A. ¿Qué más debo decir?
S.Lott
Mi pregunta es más sobre las decisiones de diseño: ¿en qué situaciones desea herencia y por qué razones? En lenguajes dinámicos, veo pocas razones para elegir la herencia sobre los mixins, además de lo que describió Raynos. El rendimiento de la creación de objetos podría ser una de las razones.
Magnus Wolffelt
@MagnusWolffelt: "¿en qué situaciones quieres herencia?" Cuando las dos clases satisfacen la relación IS-A. El "rendimiento de la creación de objetos" no es una razón para elegir uno sobre el otro. La herencia hace una declaración muy fuerte sobre las dos clases de objetos. Mixins hace una declaración más débil y más flexible. La herencia se usa cuando las dos clases satisfacen la relación "IS-A". ¿Qué más puedo decir? No puedo entender tu pregunta muy bien. ¿Puedes aclarar qué más te gustaría saber?
S.Lott
0

Bueno, el mejor ejemplo que puedo darte es un Actor para un juego que tiene herencia para algunas cosas básicas pero usa mixins / plugins para la funcionalidad compartida. La funcionalidad compartida podría ser (directamente desde el código fuente):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}
Totty.js
fuente