Ereditarietà vs mixin in linguaggi dinamici?


19

Quando dovresti preferire i modelli ereditari rispetto ai mixin in linguaggi dinamici?

Per mixin, intendo il vero e proprio mixaggio, come nell'inserimento di funzioni e membri di dati in un oggetto in fase di esecuzione.

Quando useresti, ad esempio, l'eredità prototipale anziché i mixin? Per illustrare più chiaramente cosa intendo per mixin, alcuni pseudocodici:

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

myObject = {}
asCircle(myObject)
myObject.area() // -> 0

2
Le mixin sono più simili agli aspetti trasversali che all'eredità diretta. Questo probabilmente definirà alcuni casi d'uso per te.
ashes999,

1
Composizione, chiunque :)
Onesimus Nessun impegno

Risposte:


14

L'eredità prototipica è semplice. Ha un unico vantaggio rispetto ai mixin.

Cioè è un collegamento live. se si modifica il prototipo, tutto ciò che lo eredita viene modificato.

Esempio 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;
}

Quindi, fondamentalmente, se si desidera che le modifiche al cerchio "interfaccia" si riflettano in fase di esecuzione su tutti gli oggetti che "utilizzano" la sua funzionalità, quindi ereditare da esso.

Se non si desidera che le modifiche riflettano, mescolarle.

Nota che i mixin hanno anche più scopo di quello. I mixin sono il tuo meccanismo per molteplici "eredità".

Se si desidera un oggetto di implementare molteplici "interfacce" allora si avrà bisogno di mescolare un po 'in. Quello che si utilizza per l'ereditarietà prototipo è quello che si desidera in modo da riflettere le modifiche per a run-time, gli altri saranno mescolati in.


12

Il mio senso del cavallo mi dice questo:

  • Se qualcosa è utile su più oggetti o gerarchie di classi, trasformalo in un mixin
  • Se qualcosa è solo utile lungo una gerarchia singola - utilizzare l'ereditarietà

Note correlate:

  • La parola "utile" dovrebbe essere presa metaforicamente
  • Per quelle lingue che non hanno ereditarietà multiple, i mixin sono una buona alternativa
  • PHP 5.4 introduce tratti che hanno bontà sia dai mixin che dai mondi ereditari multipli

+1, il mio esempio preferito di "qualcosa di utile su più oggetti o gerarchie di classi" in Ruby è il modulo Enumerable: ruby-doc.org/core-1.9.3/Enumerable.html
David

1
Direi che l'ereditarietà multipla può essere un'alternativa (non molto buona) ai mixin.
Simon Bergot,

@Simon Direi che i mixin possono essere un'alternativa (non molto buona) all'eredità multipla;)
Raynos,

Anche il mio senso del cavallo mi ha detto questo. :)
theringostarrs,

9

Utilizzare il test "Is-a".

L'ereditarietà è limitata al caso in cui si può dire "Sottoclasse IS A Superclass". Sono lo stesso tipo di cose. "Il formaggio è un prodotto lattiero-caseario".

I mixin sono per tutto il resto. "Il formaggio può essere usato in un panino". Il formaggio non è un panino, ma partecipa al sandwich.

PS. Questo non ha nulla a che fare con i linguaggi dinamici. Qualsiasi linguaggio con ereditarietà multipla con compilazione statica (ad es., C ++) ha lo stesso punto di decisione.


Sicuramente + 1- lingue statiche hanno anche mixin.
DeadMG

Bene, i mixin possono essere fatti in molte lingue - questa non era la mia domanda. I linguaggi dinamici hanno determinate proprietà che potrebbero o meno rendere i mixin diversi e / o più interessanti in tali linguaggi - Raynos ha sottolineato un aspetto. Inoltre, non indichi alcun motivo specifico per cui si dovrebbe usare il concetto IS A rispetto al concetto di mixin.
Magnus Wolffelt,

@MagnusWolffelt: sono lo stesso tipo di cose. "Il formaggio è un prodotto lattiero-caseario". Questa è la regola per IS-A. Cos'altro dovrei dire?
S.Lott

La mia domanda riguarda maggiormente le decisioni di progettazione: in quali situazioni desideri l'eredità e per quali motivi? Nei linguaggi dinamici vedo alcune ragioni per scegliere l'eredità rispetto ai mixin, oltre a ciò che Raynos ha descritto. Le prestazioni della creazione di oggetti potrebbero essere una delle ragioni.
Magnus Wolffelt,

@MagnusWolffelt: "in quali situazioni vuoi ereditare" Quando le due classi soddisfano la relazione IS-A. "Prestazioni nella creazione di oggetti" non è un motivo per scegliere l'uno rispetto all'altro. L'ereditarietà fa una dichiarazione molto forte sulle due classi di oggetti. Mixins rende un'affermazione più debole e flessibile. L'ereditarietà viene utilizzata quando le due classi soddisfano la relazione "IS-A". Cosa potrei dire di più? Non capisco molto bene la tua domanda. Puoi chiarire cos'altro vorresti sapere?
S.Lott

0

Bene, il miglior esempio che posso darti è un attore per un gioco che ha eredità per alcune cose di base ma usa mixin / plugin per funzionalità condivisa. La funzionalità condivisa potrebbe essere (direttamente dal codice sorgente!):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.