2016-04-20 10 views
11

Ich versuche die Mixins im Kontext von Scala zu verstehen. Insbesondere wollte ich den Unterschied zwischen den Begriffen der Vererbung und Mixins wissen. Wiki sagt, es gibt einen wichtigen Unterschied zwischen den Konzepten von Mixins und Vererbung und daher wollte ich es verstehen.Was ist der Unterschied zwischen Mixins und Vererbung?

Die Definition von Mixin in wiki sagt:

A mixin Klasse dient als der Elternklasse, die gewünschte Funktionalität enthält. Eine Unterklasse kann diese Funktionalität dann erben oder einfach wiederverwenden, , aber nicht als Mittel zur Spezialisierung. In der Regel exportiert das Mixin die gewünschte Funktionalität in eine untergeordnete Klasse, ohne eine starre, einzelne "ist eine" -Beziehung zu erstellen. Hier liegt der wichtige Unterschied zwischen den Konzepten von Mixins und Vererbung darin, dass die Kindklasse immer noch alle Merkmale der Elternklasse erben kann, aber die Semantik über das Kind, das "eine Art von" ist, muss nicht zwingend angewendet werden.

In der obigen Definition kann ich die fett markierten Aussagen nicht verstehen. Was bedeutet es, dass

  1. Eine Unterklasse Funktionalität in mixin erben kann, aber nicht als Mittel zur Spezialisierung
  2. In Mixins erbt das Kind alle Funktionen der Elternklasse aber Semantik über das Kind der „eine Art zu sein“ Eltern müssen nicht unbedingt angewendet werden. - Wie kann ein Kind einen Elternteil erweitern und nicht unbedingt eine Art Elternteil? Gibt es ein solches Beispiel?

Vielen Dank im Voraus für jede Klärung der oben genannten.

+0

In Scala, denken Sie an Mixins als eine nette Kompilierzeit-Transformation, die bestimmte Arten mit zusätzlichen Methoden schmücken wird. In diesem Fall, während Scala "gemischte Typen" für den Typüberprüfer verfolgt, werden die Methodendefinitionen selbst in den tatsächlichen Typen * abgeflacht *, so dass kein Eltern-Kind innerhalb der JVM-Klassen eingerichtet ist. Vererbung ist in der Regel mit einer Laufzeitpolymorphie-Methodenauflösung verbunden - aber Mixins sind (weitgehend) orthogonale Konzepte. Java 8-Schnittstelle Standardmethoden sind auch Mixins. – user2864740

+0

Diese Frage scheint [zuvor in einem breiteren Zusammenhang gestellt] (http://stackoverflow.com/questions/860245/mixin-vs-inheritance) gewesen zu sein (obwohl ich durch die Antworten dort nicht vollständig zufrieden bin). – badcook

Antwort

7

Ich bin mir nicht sicher, ob ich deine Frage richtig verstanden habe, aber wenn ich das tue, fragst du, wie etwas erben kann, ohne dasselbe zu meinen.

Mixins sind jedoch keine Vererbung - sie ähnelt eher dem dynamischen Hinzufügen einer Reihe von Methoden zu einem Objekt. Während das Erbe sagt "Dieses Ding ist eine Art von etwas anderem", sagen Mixins: "Dieses Objekt hat einige Eigenschaften dieses anderen Dinges." Sie können dies in dem Schlüsselwort sehen, das zum Deklarieren von Mixins verwendet wird: trait.

eklatant Um ein Beispiel aus der Scala Homepage zu stehlen:

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 diesem Fall ist die StarCruiser keine CommandoBridge oder PulseEngine; Es hat sie aber, und gewinnt die Methoden, die in diesen Merkmalen definiert sind. Es ist ein Spacecraft, wie Sie sehen können, weil es von dieser Klasse erbt.

Es ist erwähnenswert, dass, wenn ein trait erweitert class, wenn Sie etwas machen wollen with dieses Merkmal, muss es diese Klasse zu erweitern. Zum Beispiel, wenn ich eine class Dog hätte, könnte ich keine Dog with PulseEngine haben, es sei denn Dog erweitert Spacecraft. Auf diese Weise ist es nicht so, als würde man Methoden hinzufügen; Es ist jedoch immer noch ähnlich.

1

Ich denke, es spricht über die tatsächliche Klassenhierarchie. Zum Beispiel ist ein Dog ein Typ Animal, wenn es von der Klasse (Vererbung) erstreckt. Es kann überall dort verwendet werden, wo ein Animal Parameter anwendbar ist.

2

Ein Merkmal (die mixin genannt wird, wenn es mit einer Klasse gemischt) ist wie eine Schnittstelle in Java (obwohl es viele sind differences), wo Sie zusätzliche Funktionen zu einer Klasse hinzufügen können, ohne notwendigerweise „ist ein“ Beziehung. Oder Sie können sagen, dass allgemein Merkmale bündeln Funktionen, die von mehreren unabhängigen Klassen verwendet werden können.

Sie Um ein Beispiel aus Scala Bibliothek zu geben, Ordered[A] ein trait ist die Umsetzung für einige grundlegende Vergleichsoperationen (wie <, <=, >, >=) auf Klassen bietet, die Daten mit natürlichen Ordnung haben.

Zum Beispiel haben Sie Ihre eigene Klasse Number und Unterklassen EvenNumber und OddNumber wie unten gezeigt.

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 

In dem obigen Beispiel Klassen EvenNumber und OddNumber Aktien eine mit Number Beziehung sind aber EvenNumber hat nicht „ist eine“ Beziehung mit Half weder OddNumber Aktien „ist eine“ Beziehung mit Increment.

Ein weiterer wichtiger Punkt ist, obwohl Klasse Numberextends Ordered Syntax verwendet, bedeutet das, dass ein Numberimpliziteist eine Beziehung mit der übergeordneten Klasse Ordered dh Any hat.

2

Ich denke, es hängt sehr davon ab. Scala ist eine Multi-Paradigma-Sprache macht es manchmal mächtig und ein wenig verwirrend. Ich denke Mixins sind sehr mächtig, wenn sie richtig verwendet werden. Mixins sollte verwendet werden, um Verhalten einzuführen und Bolierplate zu reduzieren.

Ein Merkmal in Scala kann Implementierungen haben, und es ist verlockend, sie zu erweitern und zu verwenden.

Merkmale könnten für die Vererbung verwendet werden. Es kann auch Mixins genannt werden, aber das ist meiner Meinung nach nicht der beste Weg, mixin Verhalten zu verwenden. In diesem Fall könnten Sie sich Merkmale als Java Abstract Classes vorstellen. Wobei Sie Unterklassen erhalten, die "Typ" der Superklasse (das Merkmal) sind.

Allerdings könnte Traits auch als proper mixins verwendet werden. Die Verwendung eines Merkmals als mixin hängt von der Implementierung ab, die lautet "wie Sie es mischen". Meistens ist es eine einfache Frage, die man sich stellen sollte. Es ist "Ist die Unterklasse des Merkmals wirklich ein kind des Merkmals oder sind die Verhaltensweisen in den Merkmalsverhalten, die Boilerplate reduzieren". In der Regel wird es am besten implementiert, indem Merkmale mit Objekten gemischt werden, anstatt das Merkmal zu erweitern, um neue Klassen zu erstellen.

Zum Beispiel betrachten Sie das folgende Beispiel:

//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 ist eine Eigenschaft, die AbstractDAO erstreckt - Dies ist Erbe

val wiredObject = new service with concreteDAO - Dies ist die richtige mixin Verhalten Seit dem Dienstmerkmal beauftragt die mixin von a AbstractDAO. Es wäre einfach falsch für Service zu erweitern ConcreteDAO sowieso, weil die serviceAbstractDAO es ist keine Art von AbstractDAO. Stattdessen erstellen Sie Instanzen von service mit verschiedenen Mixins.

Verwandte Themen