2016-04-20 15 views
11

Sto cercando di capire i Mixin nel contesto di scala. In particolare volevo sapere la differenza tra i concetti di ereditarietà e Mixin. Wiki dice che c'è una differenza importante tra i concetti di mixin e ereditarietà e quindi volevo comprenderlo.Qual è la differenza tra mixin ed ereditarietà?

La definizione di Mixin in wiki dice:

classe intermedia atti a come la classe padre, che contengono la funzionalità desiderata. Una sottoclasse può quindi ereditare o semplicemente riutilizzare questa funzionalità, ma non come mezzo di specializzazione. In genere, il mixin esporta la funzionalità desiderata in una classe figlia, senza creare una relazione rigida, singola "è una". Qui sta la differenza importante tra i concetti di mixin e ereditarietà, in quanto la classe figlio può ancora ereditare tutte le caratteristiche della classe genitore, ma, la semantica sul bambino "essendo una specie di" il genitore non deve necessariamente essere applicato.

Nella definizione precedente, non sono in grado di comprendere le istruzioni contrassegnate in grassetto. cosa vuol dire che

  1. una sottoclasse può ereditare la funzionalità in mixin, ma non come un mezzo di specializzazione
  2. Nel mixins, il figlio eredita tutte le caratteristiche della classe padre, ma la semantica sul bambino "essere una specie" del il genitore non deve necessariamente essere applicato. - Come può un bambino estendere un genitore e non necessariamente un tipo di genitore? C'è un esempio del genere.

Grazie in anticipo per qualsiasi chiarimento su quanto sopra.

+0

In Scala, pensa a Mixins come a una trasformazione in fase di compilazione che decorerà determinati tipi con metodi aggiuntivi. In questo caso, mentre Scala tiene traccia dei "tipi misti" per il controllo di tipo, le definizioni dei metodi stessi sono * appiattite * nei tipi effettivi, quindi non esiste un genitore-figlio stabilito all'interno delle classi JVM. L'ereditarietà è generalmente associata a una risoluzione del metodo polimorfico di runtime - ma i mixin sono (in gran parte) concetti ortogonali. Interfaccia Java 8 I metodi predefiniti sono anche mixin. – user2864740

+0

Sembra che questa domanda sia stata [posta prima in un contesto più ampio] (http://stackoverflow.com/questions/860245/mixin-vs-inheritance) (anche se non mi sento completamente soddisfatto dalle risposte in questo campo). – badcook

risposta

7

Non sono sicuro di aver capito correttamente la tua domanda, ma se l'avessi fatto, mi stai chiedendo come qualcosa possa ereditare senza che realmente significhi la stessa cosa che ereditare.

I mixins, tuttavia, non sono ereditarietà: in realtà è più simile all'aggiunta dinamica di un insieme di metodi in un oggetto. Mentre l'eredità dice "Questa cosa è una specie di un'altra cosa", i mixin dicono: "Questo oggetto ha alcuni tratti di quest'altra cosa". Puoi vedere questo nella parola chiave usata per dichiarare i mixin: trait.

di rubare sfacciatamente un esempio dalla homepage Scala:

abstract class Spacecraft { 
    def engage(): Unit 
} 
trait CommandoBridge extends Spacecraft { 
    def engage(): Unit = { 
    for (_ <- 1 to 3) 
     speedUp() 
    } 
    def speedUp(): Unit 
} 
trait PulseEngine extends Spacecraft { 
    val maxPulse: Int 
    var currentPulse: Int = 0 
    def speedUp(): Unit = { 
    if (currentPulse < maxPulse) 
     currentPulse += 1 
    } 
} 
class StarCruiser extends Spacecraft 
        with CommandoBridge 
        with PulseEngine { 
    val maxPulse = 200 
} 

In questo caso, il StarCruiser non è un CommandoBridge o PulseEngine; it ha, tuttavia, e ottiene i metodi definiti in quei tratti. È è a Spacecraft, come puoi vedere perché eredita da quella classe.

Vale la pena ricordare che quando un trait estende una class, se si vuole fare qualcosa di with quel tratto, si deve estendere tale classe. Ad esempio, se avessi uno class Dog, non potrei avere uno salvo Dog esteso Spacecraft. In questo modo, non è proprio come aggiungere metodi; tuttavia, è ancora simile.

1

Penso che stia parlando dell'effettiva gerarchia delle classi. Ad esempio, un Dog è un tipo di Animal se si estende dalla classe (ereditarietà). Può essere utilizzato ovunque sia applicabile un parametro Animal.

2

Un trait (che si chiama mixin se mescolato con una classe) è come un'interfaccia in Java (anche se ci sono molti differences) in cui è possibile aggiungere ulteriori funzionalità a una classe senza avere necessariamente "è una" relazione. In alternativa, puoi dire che i caratteri generalmente includono e che possono essere utilizzati da più classi indipendenti.

Per darvi un esempio dalla libreria Scala, Ordered[A] è un trait che prevede l'attuazione di alcune operazioni di confronto di base (come <, <=, >, >=) per le classi che possono avere i dati con ordinamento naturale.

Ad esempio, supponiamo di avere la propria classe Number e sottoclassi EvenNumber e OddNumber come illustrato di seguito.

class Number(val num : Int) extends Ordered[Number] { 
    override def compare(that : Number) = this.num - that.num 
} 

trait Half extends Number { 
    def half() = num/2 
} 

trait Increment extends Number { 
    def increment() = num + 1 
} 

class EvenNumber(val evenNum : Int) extends Number(evenNum) with Half 

class OddNumber(val oddNum : Int) extends Number(oddNum) with Increment 

Nell'esempio precedente, classi EvenNumber e OddNumber share è una relazione con Number ma EvenNumber non ha "è un" rapporto con HalfOddNumber condividere "è un" rapporto con Increment.

Un altro importante punto è pur classe Number utilizza extends Ordered sintassi, significa che Number ha un implicitoè una relazione con superclasse di Ordered cioè Any.

2

Penso che sia molto dipendente dall'utilizzo. Scala è un linguaggio multi-paradigma che lo rende potente e un po 'confuso, a volte. Penso che i Mixin siano molto potenti se usati nel modo giusto. Le miscele devono essere utilizzate per introdurre comportamenti e ridurre la boliera.

Un tratto in Scala può avere implementazioni e si è tentati di estenderle e utilizzarle.

I tratti possono essere utilizzati per ereditarietà. Può anche essere chiamato mixins, tuttavia, a mio parere, non è il modo migliore per utilizzare il comportamento di mixin. In questo caso potresti pensare a tratti come classi astratte Java. In cui ottieni sottoclassi che sono "tipo di" la super classe (il tratto).

Tuttavia i caratteri possono essere utilizzati anche come proper mixins. Ora usare un tratto come mixin dipende dall'implementazione che è "come lo si mescola". Per lo più è una semplice domanda da porsi. È "La sottoclasse del tratto è veramente un kind tratto o sono i comportamenti nei comportamenti tratto che riducono lo standard". In genere è meglio implementare mescolando i tratti agli oggetti piuttosto che estendere il tratto per creare nuove classi.

Ad esempio si consideri il seguente esempio:

//All future versions of DAO will extend this 
trait AbstractDAO{ 
    def getRecords:String 
    def updateRecords(records:String):Unit 
} 
//One concrete version 
trait concreteDAO extends AbstractDAO{ 
    override def getRecords={"Here are records"} 
    override def updateRecords(records:String){ 
    println("Updated "+records) 
    } 
} 
//One concrete version 
trait concreteDAO1 extends AbstractDAO{ 
    override def getRecords={"Records returned from DAO2"} 
    override def updateRecords(records:String){ 
    println("Updated via DAO2"+records) 
    } 
} 
//This trait just defines dependencies (in this case an instance of AbstractDAO) and defines operations based over that 
trait service{ 
    this:AbstractDAO => 

    def updateRecordsViaDAO(record:String)={ 
    updateRecords(record) 
    } 
    def getRecordsViaDAO={ 
    getRecords 
    } 
} 


object DI extends App{ 
    val wiredObject = new service with concreteDAO //injecting concrete DAO to the service and calling methods 
    wiredObject.updateRecords("RECORD1") 
    println(wiredObject.getRecords) 

    val wiredObject1 = new service with concreteDAO1 
    wiredObject1.updateRecords("RECORD2") 
    println(wiredObject1.getRecords) 

} 

concreteDAO è un tratto che si estende AbstractDAO - Questo è eredità

val wiredObject = new service with concreteDAO - Questo è corretto comportamento mixin Poiché il tratto servizio mandati l'mixin di a AbstractDAO. Sarebbe semplicemente sbagliato per Service estendere lo ConcreteDAO perché il service richiesto AbstractDAO non è un tipo di AbstractDAO. Invece si creano istanze di service con diversi mixin.

Problemi correlati