2013-06-23 8 views
7

私は、Scalaの不変のプリンシパルにとどまることを学ぶ多くの問題に遭遇しているようです。その1つは問題のオブジェクトからクローニング(またはむしろ派生)の概念です。不変のクラスと特性?

これらの問題の一つは、特性における混合の概念である - たとえば

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 

} 

今これは非表示にするには、私はすでに様々なクラスを中心に、今日作っていたより複雑な問題、ファクトリメソッドの本当にシンプルなバージョンです。クラスAなどがあります。私たちが一つの形質しか扱っていないなら、私は単にそれをテストし、必要に応じて転送することができます。しかし、3つ以上の形質が存在する可能性がある場合、私は何をしますか?私は非現実的なすべての組み合わせをテストする必要があります。

機能的なデザインプリンシパルを遵守しながら、既存のオブジェクトをさまざまな特質でインスタンス化(クローン)したり、その一部を変更したりするにはどうすればよいですか?

多くのおかげで、 - ティム

+0

これはまったく簡単なことです。これは私がケーキパターンを避けようとする主な理由の1つです。同じケーキを作り直すのは本当に面倒です。振る舞いを変更するものがデータ(例えば、おそらくコンストラクタ内のクラスの 'val')であれば一般的に簡単です。 –

+0

私は同意して悲しげに私がこのパターンを飾る特性を避け続けるのは同然です...それは本の中ではすばらしいようですが、ここで概説したように、後でオブジェクトをクローンする方法については学問の本では決して言及しません。 – LaloInDublin

+0

基本的には、オブジェクトのビルダーを作成しなければなりません。このビルダーでは、特性を混在させるたびに別の3〜4行の定型文を追加します。時にはまだ価値があります。しばしばそうではありません。 –

答えて

3

コレクションあなたが開始しているものから、ターゲット・タイプを生成する方法を知っている暗黙のビルダーを使用しています。これら2つのタイプは必ずしも同じものではありません。

例えば製造することができるかを制御タイプセーフビルダー、およそ多くの関連記事がありますが、 http://nullary.blogspot.com/2011/10/builder-pattern-revisited-in-scala.html

関連する質問で何を混在型のコレクションがある場合:値に Polymorphic updates in an immutable class hierarchy

を軸、符号化タイプの代わりにトラッキング値 What is the Scala equivalent to a Java builder pattern?

更新:再生時に類似したものがありました。パターンにREを使用することについては、MLおよびhereに記載されています。

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) = ??? 
    } 
} 

タイプパラメータでimplicitsを制御する方法と代替方法を使用します。

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" 
    } 
}