Mixin vs eredità


Risposte:


66

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.


29

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.

Mixin in confronto e contrasto con classi di base astratte

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 abcmodulo 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.

Sommario

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.


18

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.


7

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.


Faccio fatica a capire la frase in grassetto. Suona come "la differenza (di B?) Da A è che (B?) Ha bisogno di qualcosa come in A". Stai parlando di differenza o somiglianza?
RayLuo

@ RayLuo Whoops ... Ho fatto un errore di battitura. Scusa se ti confondo. I mix-in NON hanno bisogno di avere una relazione "è-un"
Alex

3

"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à.


0

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 Malla classe C, Cdovrebbe fornire il sayHello()metodo.


1
non sono sicuro della correttezza della tua prima affermazione - le classi possono definire i propri metodi
EugeneMi

0

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 MrTmodulo può essere utilizzato in questo modo:

use MrT;

MrT->new()->pity();

So che è un esempio assurdo, ma capisce bene ...


0

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

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.