2013-06-23 20 views
7

Ich scheine viele Probleme zu haben, mit unveränderlichen Prinzipien in Scala zu bleiben, von denen eines das Konzept des Klonens (oder eher Ableitens) von dem fraglichen Objekt ist.Unveränderliche Klassen und Eigenschaften?

Eines dieser Probleme ist das Konzept der gemischten in Zügen - Beispiel

trait helper //modifies some kind behavior.. assume we want to to continue down the line 

class A (val x:int) { 

def add(y:int) = new A(x + y) 
} 

Example extends App { 

val a =new A(5) with helper 
val b = a.add(10) // mixed trait disappears 

} 

Nun ist diese nur eine wirklich einfache Version eines komplexeren Problem ist, habe ich heute schon um verschiedene Klassen gebaut, Factory-Methoden zu verstecken Klasse A usw. Wenn wir nur mit einem Merkmal arbeiten, weiß ich, dass ich es einfach testen und nach Bedarf weiterleiten könnte. Aber was zum Teufel mache ich, wenn ab 3 oder mehr Charakterzüge existieren könnten? Ich müsste für alle Kombinationen testen, was unrealistisch ist.

Wie instanziieren (klonen) Sie ein existierendes Objekt mit verschiedenen Merkmalen und/oder modifizieren Sie einige Aspekte davon, während Sie den funktionalen Designprinzipien folgen?

Vielen Dank, - Tim

+0

Es stellt sich heraus, überhaupt nicht einfach zu sein! Dies ist einer der Hauptgründe, warum ich versuche, das Kuchenmuster zu vermeiden - es ist wirklich schwierig, den gleichen Kuchen herzustellen, besonders wenn man den Kuchen im Handumdrehen baut. Es ist im Allgemeinen einfacher, wenn das, was Verhalten verändert, Daten sind (z. B. ein "val" in der Klasse, wahrscheinlich im Konstruktor). –

+0

Ich stimme zu, und leider vermeide ich auch das Muster der Eigenschaftsverzierung ... es sieht gut in einem Buch aus, aber die akademischen Bücher befassen sich nie damit, wie man das Objekt später klont, wie ich hier beschrieben habe. – LaloInDublin

+0

Sie müssen grundsätzlich einen Builder für das Objekt erstellen, der jedes Mal, wenn Sie das Merkmal mischen möchten, weitere drei oder vier Zeilen Boilerplate (wenn ich es tue) hinzufügt. Manchmal lohnt es sich immer noch. Oft ist es nicht. –

Antwort

3

Kollektionen verwendet implizite Builder, die wissen, wie Ihre Zieltyp aus zu produzieren, was Sie beginnen mit. Diese zwei Arten sind nicht immer das Gleiche.

Es gibt viele ähnlichen Beiträge über typsichere Builder, die etwas steuern kann hergestellt werden, beispielsweise http://nullary.blogspot.com/2011/10/builder-pattern-revisited-in-scala.html

Eine weitere Frage ist, was passiert, wenn Sie eine Sammlung von Mischtypen: Polymorphic updates in an immutable class hierarchy

Auf dem Wert Achse, Tracking-Werte anstelle von Codierungstypen What is the Scala equivalent to a Java builder pattern?

Aktualisiert: etwas ähnliches kam gerade während der Spielzeit auf. Die Verwendung von REs in Mustern ist in der ML und here beschrieben.

package object interpat { 
    implicit class MySContext (val sc : StringContext) { 
    object mys { 
     def apply (args : Any*) : String = sc.s (args : _*) 
     def unapplySeq (s : String) : Option[Seq[String]] = { 
     val regexp = sc.parts.mkString ("(.+)").r 
     regexp.unapplySeq (s) 
     } 
    } 
    } 
    implicit class SBContext (val sc : StringContext) { 
    def sb(args: Any*): SB = new SB(sc.s (args : _*)) 
    } 
    implicit class toHasPattern(sb: SB) { 
    def /(pp: String) = new SB(sb.s) with HasPattern { 
     val p = pp 
    } 
    } 
    implicit class toHasRepl(hasp: SB with HasPattern) { 
    def /(rr: String) = new SB(hasp.s) with HasPattern with HasRepl with Updateable { 
     val p = hasp.p 
     val r = rr 
    } 
    } 
    // disallow it 
    implicit class noway(hasr: SB with HasPattern with HasRepl) { 
    def /(rr: String) = ??? 
    } 
    implicit class noway2(hasr: SB with HasPattern with HasRepl) { 
    def /(rr: String) = ??? 
    } 
} 

Mit Verwendungen und Alternative der Steuerung der implicits mit Typparametern.

package interpat { 
    import scala.util.Try 
    object I { def unapply(x: String): Option[Int] = Try(x.toInt).toOption } 

    trait XX { 
    type HasIt 
    type Yes <: HasIt 
    type No <: HasIt 
    } 
    object XX extends XX { 
    implicit class XContext (val sc : StringContext) { 
     def x(args: Any*) = new X[No, No] { 
     val s = sc.s(args : _*) 
     } 
    } 
    implicit class xPat(x: X[No, No]) { 
     def /(pp: String) = new X[Yes, No] with HasPattern { 
     val s = x.s 
     val p = pp 
     } 
    } 
    implicit class xRep(x: X[Yes, No] with HasPattern) { 
     def /(rr: String) = new X[Yes, Yes] with HasPattern with HasRepl { 
     val s = x.s 
     val p = x.p 
     val r = rr 
     override def toString = s replaceAll (p, r) 
     } 
    } 
    implicit class xable(xx: X[Yes, Yes]) { 
     def x = xx.toString 
    } 
    } 
    import XX._ 

    trait X[HasP <: HasIt, HasR <: HasIt] { 
    def s: String 
    } 

    trait HasPattern { 
    def p: String 
    } 

    trait HasRepl { 
    def r: String 
    } 

    trait Updateable { this: HasPattern with HasRepl => 
    def update(p: String, r: String) 
    override def toString = { 
     update(p, r) 
     super.toString 
    } 
    } 

    class SB(val s: String) { 
    final val sb = new StringBuilder(s) 
    def update(p: String, r: String): Unit = 
     sb.replace(0, sb.length, sb.toString.replaceAll(p, r)) 
    override def toString = sb.toString 
    } 

    object Test extends App { 
    val msg = "The sky is blue" match { 
     case mys"The $thing is $colour" => mys"A $colour thing is $thing" 
     case _ => "no match" 
    } 
    println (msg) 
    val mys"The $thing is $colour" = "The sky is blue" 
    Console println s"$thing/$colour" 
    val mys"The ${I(number)} is blue" = "The 3 is blue" 
    Console println s"$number" 
    //sb"The sky is blue".update("blue","red") 
    // no way to get a value out! 
    sb"The sky is blue"("blue") = "red" 
    val ugh = sb"The sky is blue" 
    ugh("blue") = "red" 
    Console println ugh 
    val sx = sb"The sky is $colour"/"blue"/"red" 
    Console println sx 
    //sb"The sky is $colour"/"blue"/"red"/"yellow" 
    Console println sx 
    Console println x"The sky is $colour"/"blue"/"red" 
    Console println (x"The sky is $colour"/"blue"/"red").x 
    //Console println x"The sky is $colour"/"blue"/"red"/"yellow" 
    } 
} 
Verwandte Themen