2016-07-25 8 views
1

Ich habe eine Eigenschaft, die die folgenden:Abstracting Allgemeines Verhalten mit Traits in Scala

trait MyTrait[T] { 
    def doSomething(elems: Seq[T]) 
} 

ich dann eine Fabrik haben, die Instanzen der Implementierungen dieses Merkmals schaffen würde:

object MyTrait { 
    def apply(): MyTrait = { 
    new StringTrait() 
    } 
} 

Jetzt Die konkrete Implementierung sieht so aus:

class StringTrait extends MyTrait[String] { 
    def doSomething(elems: Seq[String]) = { 
    // some generic logic here 
    // some specific logic here (this code bit depends on the type of implementation) 
    // some generic logic here 
    } 
} 

Wie könnte ich jetzt StringTrait so machen, dass ich reinkomme spezifisches Verhalten von ihm und die generische Logik in einer abstrakten Klasse definiert? Eine Möglichkeit wäre, das Verhalten als Thunk zu übergeben, aber das bedeutet, dass ich meine doSomething (...) -Methode ändern muss, um einen zusätzlichen Parameter zu nehmen, den ich lieber vermeiden würde.

Antwort

0

Sie haben ein paar Optionen, aus Gründen der Illustration nehme ich an, dass das typenspezifische Verhalten ein Seq [T] => T ist (dh Sie nehmen eine Folge von T und erzeugen ein T als Ergebnis):

Vererbung basiert:

trait MyTrait[T] { 
    def doTypeSpecificStuff(a: Seq[T]): T 

    def doSomething(elems: Seq[T]): T = { 
    // generic code stuff 
    val t: T = doTypeSpecificStuff(elems) 
    // more generic code 
    t 
    } 
} 

class StringTrait extends MyTrait[String] { 
    def doTypeSpecificStuff(elems: Seq[String]) = { 
    elems.reduceOption(_ + _).getOrElse("") 
    } 
} 

def client(thing: MyTrait[String], elems: Seq[String]) { 
    thing.doSomething(elems) 
} 

Typklasse:

trait MyTypeClass[T] { 
    def doTypeSpecificStuff(a: Seq[T]): T 
} 

object StringTypeClass { 
    implicit val instance: StringTypeClass = new StringTypeClass() 
} 

class StringTypeClass extends MyTypeClass[String] { 
    def doTypeSpecificStuff(elems: Seq[String]): String = { 
    elems.reduceOption(_ + _).getOrElse("") 
    } 
} 

object TypeClassDependentBehaviour { 
    def doSomething[T](elems: Seq[T])(implicit tp: MyTypeClass[T]): T ={ 
    //some code 
    val stuff: T = tp.doTypeSpecificStuff(elems) 
    //more generic code 
    stuff 
    } 
} 

def client(elems: Seq[String]) { 
    TypeClassDependentBehaviour.doSomething(elems) 
}