Héritage vs mixins dans les langages dynamiques?

19

Quand devriez-vous préférer les modèles d'héritage aux mixins dans les langages dynamiques?

Par mixins, j'entends un véritable mixage, comme lors de l'insertion de fonctions et de membres de données dans un objet lors de l'exécution.

Quand utiliseriez-vous, par exemple, l'héritage prototypique au lieu des mixins? Pour illustrer plus clairement ce que je veux dire par mixin, un pseudocode:

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

myObject = {}
asCircle(myObject)
myObject.area() // -> 0
Magnus Wolffelt
la source
2
Les mixins ressemblent plus à des aspects transversaux qu'à l'héritage direct. Cela définira probablement certains cas d'utilisation pour vous.
ashes999
1
Composition, n'importe qui :)
OnesimusUnbound

Réponses:

14

L'héritage prototypique est simple. Il a un seul avantage sur les mixins.

C'est que c'est un lien en direct. si vous changez le prototype, tout ce qui en hérite est changé.

Exemple utilisant 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;
}

Donc, fondamentalement, si vous souhaitez que les modifications apportées au cercle "interface" se répercutent au moment de l'exécution sur tous les objets qui "utilisent" sa fonctionnalité, héritez-en.

Si vous ne voulez pas que les changements soient reflétés, mélangez-les.

Notez que les mixins ont également plus de fonction que cela. Les mixins sont votre mécanisme d'héritage multiple.

Si vous voulez qu'un objet implémente plusieurs "interfaces", vous devrez en mélanger quelques-unes. Celui que vous utilisez pour l'héritage prototypique est celui que vous souhaitez que les modifications reflètent au moment de l'exécution, les autres seront mélangés.

Raynos
la source
12

Mon sens du cheval me dit ceci:

  • Si quelque chose est utile sur plusieurs objets ou hiérarchies de classes - faites-en un mixage
  • Si quelque chose est seulement utile le long d' une seule hiérarchie - l' héritage d'utilisation

Notes connexes:

  • Le mot «utile» doit être pris métaphoriquement
  • Pour les langues qui n'ont pas d'héritage multiple, les mixins sont une bonne alternative
  • PHP 5.4 introduit des traits qui ont du bien à la fois dans les mixins et dans les multiples mondes d'héritage
treecoder
la source
+1, mon exemple préféré de "quelque chose d'utile sur plusieurs objets ou hiérarchies de classes" dans Ruby est le module Enumerable
David
1
Je dirais que l'héritage multiple peut être une alternative (pas si bonne) aux mixins.
Simon Bergot
@Simon, je dirais que les mixins peuvent être une alternative (pas si bonne) à l'héritage multiple;)
Raynos
Mon sens du cheval me l'a dit aussi. :)
theringostarrs
9

Utilisez le test "Is-a".

L'héritage est limité au cas où vous pouvez dire "La sous-classe EST une super-classe". C'est le même genre de chose. "Le fromage est un produit laitier".

Les mixins sont pour tout le reste. "Le fromage peut être utilisé dans un sandwich". Le fromage n'est pas un sandwich, mais il participe au sandwich.

PS. Cela n'a rien à voir avec les langages dynamiques. Tout langage d'héritage multiple avec compilation statique (c'est-à-dire C ++) a le même point de décision.

S.Lott
la source
Certainement + 1- les langages statiques ont aussi des mixins.
DeadMG
Bon, les mixins peuvent être faits dans de nombreuses langues - ce n'était pas ma question. Les langages dynamiques ont certaines propriétés qui peuvent ou non rendre les mixins différents et / ou plus intéressants dans ces langages - Raynos a souligné un aspect. De plus, vous ne mentionnez aucune raison particulière pour laquelle on devrait utiliser le concept IS A par rapport au concept mixin.
Magnus Wolffelt
@MagnusWolffelt: C'est le même genre de chose. "Le fromage est un produit laitier". C'est la règle pour IS-A. Que dire de plus?
S.Lott
Ma question concerne davantage les décisions de conception - dans quelles situations souhaitez-vous l'héritage et pour quelles raisons? Dans les langages dynamiques, je vois peu de raisons de choisir l'héritage plutôt que les mixins, en plus de ce que Raynos a décrit. Les performances de la création d'objets peuvent être une des raisons.
Magnus Wolffelt
@MagnusWolffelt: "dans quelles situations voulez-vous l'héritage" Lorsque les deux classes satisfont la relation IS-A. La «performance de création d'objet» n'est pas une raison pour choisir l'un plutôt que l'autre. L'héritage fait une déclaration très forte sur les deux classes d'objets. Mixins fait une déclaration plus faible et plus flexible. L'héritage est utilisé lorsque les deux classes satisfont la relation "IS-A". Que dire de plus? Je ne comprends pas très bien votre question. Pouvez-vous préciser ce que vous aimeriez savoir de plus?
S.Lott
0

Eh bien, le meilleur exemple que je puisse vous donner est un acteur pour un jeu qui a l'héritage de certains trucs de base mais utilise des mixins / plugins pour des fonctionnalités partagées. La fonctionnalité partagée pourrait être (directement à partir du code source!):

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