Risposte:
Un mixin viene generalmente utilizzato con ereditarietà multipla. Quindi, in questo senso, "non c'è differenza".
Il dettaglio è che un mixin è raramente utile come oggetto autonomo.
Ad esempio, supponiamo di avere un mixin denominato "ColorAndDimension", che aggiunge una proprietà color e larghezza e altezza.
Ora, potresti aggiungere ColorAndDimension a, ad esempio, una classe Shape, una classe Sprite, una classe Car, ecc. E avranno tutti la stessa interfaccia (ad esempio get / setColor, get / setHeight / Width, ecc.)
Quindi, nel caso generico, un mixin è eredità. Ma si può sostenere che è una questione di ruolo della classe nel dominio generale se un mixin è una classe "primaria" o semplicemente un mixin.
Modifica - solo per chiarire.
Sì, un mixin può essere considerato, nel gergo moderno di oggi, un'interfaccia con un'implementazione associata. In realtà è solo un'eredità multipla semplice, vecchia, quotidiana che utilizza una classe semplice, vecchia, quotidiana. È solo un'applicazione specifica dell'MI. La maggior parte delle lingue non attribuisce a un mixin uno status speciale; è solo una classe che è stata progettata per essere "mescolata", piuttosto che usata da sola.
Qual è la differenza tra un mixin e l'ereditarietà?
Un mix-in è una classe base da cui puoi ereditare per fornire funzionalità aggiuntive. Esempio di pseudocodice:
class Mixin:
def complex_method(self):
return complex_functionality(self)
Il nome "mix-in" indica che è destinato ad essere mescolato con altro codice. In quanto tale, la conclusione è che non istanzeresti la classe mista da sola. Il seguente oggetto non ha dati e non ha senso istanziarlo per chiamare complex_method. (Puoi anche definire una funzione invece di una classe in quel caso.)
>>> obj = Mixin()
Spesso il mix-in viene utilizzato con altre classi base.
Pertanto i mixin sono un sottoinsieme, o un caso speciale, di ereditarietà.
I vantaggi dell'utilizzo di un mix-in rispetto all'ereditarietà singola sono che è possibile scrivere codice per la funzionalità una sola volta e quindi utilizzare la stessa funzionalità in più classi diverse. Lo svantaggio è che potresti dover cercare quella funzionalità in luoghi diversi da dove viene utilizzata, quindi è bene mitigare tale svantaggio tenendola vicina.
Personalmente ho trovato un mix-in necessario da utilizzare su una singola ereditarietà in cui stiamo unittestando un sacco di codice simile, ma i casi di test sono istanziati in base alla loro eredità di un caso di base e l'unico modo per mantenere il codice vicino a hand (e nello stesso modulo), senza interferire con i numeri di copertura, deve ereditare da object e fare in modo che i casi figlio ereditino sia dalla base del caso di test universale che dalla base personalizzata che si applica solo a loro.
Entrambi sono una forma di classe genitore che non deve essere istanziata.
Un mixin fornisce funzionalità, ma non è in grado di utilizzarlo direttamente. Un utente deve usarlo tramite una (sotto) classe.
Una classe base astratta fornisce un'interfaccia, ma senza funzionalità utilizzabile. Un utente è destinato a creare la funzionalità chiamata dall'interfaccia.
class Abstraction(metaclass=abc.ABCMeta):
@abc.abstractmethod
def complex_method(self):
return complex_functionality(self)
Qui ti viene impedito di creare un'istanza di questo oggetto perché richiede una sottoclasse per implementare la funzionalità con un metodo concreto (sebbene tu possa accedere alla funzionalità all'interno da super()
):
>>> obj = Abstraction()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Abstraction with
abstract methods complex_method
In Python, alcune classi nel abc
modulo sono esempi di classi genitore che forniscono entrambe funzionalità tramite ereditarietà e interfacce astratte che devono essere implementate dalla sottoclasse. Queste idee non si escludono a vicenda.
In parole povere, un mix-in è solo una classe base che non istanzeresti da sola e in genere utilizzata come classe base secondaria con ereditarietà multipla.
il mix-in è un caso specifico e limitato di eredità (multipla) utilizzato per scopi di implementazione; alcuni linguaggi (ad esempio Ruby) lo supportano senza supportare l'ereditarietà multipla generalizzata.
Il mixin è un concetto astratto e tutto ciò che soddisfa i suoi requisiti può essere considerato un mixin.
Ecco una definizione da Wikipedia.
Nei linguaggi di programmazione orientati agli oggetti, un mixin è una classe che contiene metodi per l'utilizzo da parte di altre classi senza dover essere la classe genitore di quelle altre classi. Il modo in cui quelle altre classi accedono ai metodi di mixin dipende dalla lingua. I mixin sono talvolta descritti come "inclusi" piuttosto che "ereditati".
In breve, la differenza fondamentale rispetto a un'eredità è che i mix-in NON hanno bisogno di avere una relazione "è-un" come nell'eredità.
Dal punto di vista dell'implementazione, puoi pensarlo come un'interfaccia con le implementazioni. Ad esempio, una classe astratta in Java potrebbe essere considerata un mixin se Java supportasse l'ereditarietà multipla.
"Un mixin è un frammento di una classe nel senso che deve essere composto con altre classi o mixin." -DDJ
Un mixin è una classe o un frammento di codice che non è inteso per uso autonomo, ma invece dovresti usarlo all'interno di un'altra classe. O componendolo come un campo membro / variabile o come un segmento di codice. Ho la maggiore esposizione al dopo. È un po 'meglio che copiare e incollare il codice boilerplate.
Ecco un ottimo articolo su DDJ che introduce l'argomento.
Half-Life 2 / "Source" SDK è un ottimo esempio di mixin C ++. In quell'ambiente le macro definiscono blocchi di codice considerevoli che possono essere aggiunti per dare alla classe un "sapore" o una caratteristica specifica.
Guarda l'esempio wiki di origine: Authoring a Logical Entity . Nel codice di esempio la macro DECLARE_CLASS può essere considerata un mixin. Source SDK utilizza ampiamente i mixin per standardizzare il codice di accesso ai dati e attribuire comportamenti alle entità.
Con l'ereditarietà multipla, la nuova classe può essere composta da più superclassi. È possibile chiamare solo metodi definiti in una qualsiasi delle superclassi.
D'altra parte, mixin è una sottoclasse astratta che può essere utilizzata per specializzare il gruppo di una varietà di classi genitoriali. I mixin possono chiamare un metodo (ad esempio sayHello(): String
) anche se non definiscono tale metodo.
mixin M {
name: String
defmethod greetings() { print sayHello() + " " + name}
}
Come vedi, puoi chiamare sayHello()
anche se non è definito da nessuna parte. Se aggiungi il mixin M
alla classe C
, C
dovrebbe fornire il sayHello()
metodo.
Penso che sia importante notare che il mixin non implica l' ereditarietà . Secondo wikipedia, un Mixin è:
Nei linguaggi di programmazione orientati agli oggetti, un mixin è una classe che contiene metodi per l'utilizzo da parte di altre classi senza dover essere la classe genitore di quelle altre classi. Il modo in cui quelle altre classi accedono ai metodi di mixin dipende dalla lingua. I mixin sono talvolta descritti come "inclusi" piuttosto che "ereditati".
Nello specifico, in un linguaggio come perl, i mixin possono essere aggiunti utilizzando il modulo Exporter:
package Mixins;
use Exporter qw(import);
our @EXPORT_OK = qw(pity);
# assumes it will be mixed-in to a class with a _who_do_i_pity method
sub pity {
my ($self) = @_;
printf("I pity %s\n", $self->_who_do_i_pity('da foo'));
}
Che può essere mischiato a qualsiasi modulo contenente uno o più metodi alla volta:
package MrT
use Mixins qw(pity);
sub new {
return bless({}, shift);
}
sub _who_do_i_pity {
return 'da foo!'
}
Quindi nel tuo MrT
modulo può essere utilizzato in questo modo:
use MrT;
MrT->new()->pity();
So che è un esempio assurdo, ma capisce bene ...
tl; dr
mixin e ereditarietà multipla hanno la stessa forma. Ma hanno una semantica diversa: mixin ha le classi di base che forniscono l'implementazione della funzione. Per l'ereditarietà, le classi base forniscono l'interfaccia e la sottoclasse ha l'implementazione.
Tuttavia, la composizione è preferita rispetto alla miscelazione IMO