2016-04-20 9 views
11

私はスカラの文脈でミックスインを理解しようとしています。特に私は継承の概念とミックスインの違いを知りたがっていました。 Wikiには、ミックスインと継承の概念の間に重要な違いがあり、それを理解したかったと言います。mixinと継承の違いは何ですか?

wikiでのミックスインの定義はこう述べています。

ミックスインクラスは、所望の機能性を含む、親クラスとして機能します。サブクラスは、この機能を継承するか、または単に再利用することができますが、の特殊手段としては使用できません。通常、mixinは厳密な単一の "is a"関係を作成せずに、目的の機能を子クラスにエクスポートします。ここでは、ミックスインと継承の概念の重要な違いがあります。子クラスは親クラスのすべての機能を引き継ぐことができますが、は、「親の一種」であることに関するセマンティクスが必ずしも適用される必要はありません

上記の定義では、太字で記されたステートメントは理解できません。それは

  1. サブクラスがミックスインで機能を継承することができますが、ミックスインで専門
  2. の手段として、子供は「一種である」子について、すべての親クラスの機能が、セマンティクスを継承していないことを何を意味しています親は必ずしも適用される必要はない。 - 子供は親をどのようにして拡張することができますか、必ずしも一種の親ではないでしょうか?そのような例がありますか?

上記のことについて事前にご理解いただきありがとうございます。

+0

Scalaでは、Mixinsは、余分なメソッドで特定の型を飾るきちんとしたコンパイル時変換と考えてください。この場合、Scalaは型チェッカーの "mixed in types"を追跡しますが、メソッド定義自体は実際の型にフラット化されているので、JVMクラス内に親子が設定されていません。継承は、一般に実行時の多型メソッド解決に関連しますが、ミックスインは(ほぼ)直交する概念です。 Java 8のインターフェースデフォルトのメソッドはmixinsです。 – user2864740

+0

この質問は(私はそこの答えで完全に満足しているとは思わないが)[もっと広いコンテキストで前に尋ねられた]ようだ(http://stackoverflow.com/questions/860245/mixin-vs-inheritance)。 – badcook

答えて

7

私はあなたの質問を適切に理解しているかどうかはわかりませんが、私がした場合、継承するものと同じ意味を持たずに何かを継承できるかを尋ねています。

ミックスインは継承ではありません。実際には、オブジェクトに一連のメソッドを動的に追加する方が似ています。 "この物は別のものの一種です"と言われていますが、ミックスインはこう言っています。 "この物はこの他の物の特徴をいくつか持っています。あなたはmixinsを宣言するのに使用されるキーワード:traitでこれを見ることができます。露骨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 
} 

StarCruiserCommandoBridge又はPulseEngineありません。しかしにはがあり、これらの特性で定義されているメソッドが得られます。 Spacecraftです。これは、そのクラスから継承しているためです。

traitclassの場合は、withという特性を作りたい場合は、そのクラスを拡張する必要があります。たとえば、class Dogがある場合、DogSpacecraftに拡張しないと、Dog with PulseEngineを取得できませんでした。そういう意味では、メソッドを追加するのに似ているわけではありません。しかし、それはまだ似ています。あなたは、必ずしも「ある」ことなく、クラスに機能を追加することができます(differences多くがありますが)

1

私はそれが実際のクラス階層について話していると思います。たとえば、Dogは、クラス(継承)から継承される場合はAnimalの型です。 Animalパラメータが適用できる場合は、いつでも使用できます。

2

(クラスと混合したときにミックスインと呼ばれている)トレイトは、Javaのインターフェイスのようなものです関係。あるいは、と一般的には、の特性は複数の独立したクラスで使用できる特徴をまとめます。 Scalaのライブラリーからあなたの例を与えることを

Ordered[A]は自然順序付けを使用してデータを持つことができるのクラスに(<<=>>=のような)いくつかの基本的な比較演算の実装を提供traitです。

たとえば、あなた自身のクラスNumberとサブクラスEvenNumberOddNumberがあるとします。上記の例では

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 

、クラスEvenNumberOddNumberシェアNumberの関係であるが、Halfとの関係でもないOddNumberシェア「です」EvenNumberありませんIncrementとの関係「です」。

もう一つの重要な点は、クラスNumberextends Ordered構文を使用していても、それはNumber暗黙のOrderedすなわちAnyのスーパークラスと関係であることを意味しています。

2

私はその非常に使い方に依存していると思います。 Scalaはマルチパラダイム言語であるため、時には混乱を招くだけでなく、強力になります。 ミックスインは正しい方法で使用すると非常に強力だと思います。 ミックスインを使用して行動を導入し、bolierplateを減らす必要があります。

Scalaの特性は実装を持つことができ、拡張して使用することができます。

形質を継承に使用することができました。私の意見では、mixinの動作を使用する最善の方法ではありませんが、mixinsと呼ばれることもあります。この場合、特性をJava抽象クラスと考えることができます。スーパークラス(型)の「タイプ」であるサブクラスを取得します。

ただし、形質はproper mixinsとしても使用できます。 mixinとしての特性を使用することは、「どのように混ぜるか」という実装に依存します。主にあなた自身に尋ねる簡単な質問です。 「形質のサブクラスは本当に形質のkindであるか、定型文を減少させる形質行動における振る舞い」である。 通常は、特性を拡張して新しいクラスを作成するのではなく、オブジェクトに特性をミックスすることによって最適に実装されます。例えば

は、次の例を検討:

//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) 

} 

concreteDAOAbstractDAOを拡張する形質である - これは、継承

val wiredObject = new service with concreteDAOある - サービス形質はのmixinを義務付けたので、これは適切なミックスインの動作 ですa AbstractDAOserviceが要求されているため、AbstractDAOAbstractDAOのタイプではないため、ServiceConcreteDAOを延長するのは間違いです。 代わりに異なるmixinでserviceのインスタンスを作成します。

関連する問題