2

class を持つ不変のライブラリがあると仮定しましょうImmutableFoo:

scala> class ImmutableFoo(x: Int) {
         def add(y: Int): ImmutableFoo = new ImmutableFoo(x + y)
       }
defined class ImmutableFoo

もちろん、このクラスのオブジェクトは に追加yすることによってその状態を変更するのではなくx、クラスの新しいオブジェクトを作成します。ここまでは順調ですね。

次に、不変のサブクラスを作成します。初挑戦:

scala> class subImmutableFoo(x: Int) extends ImmutableFoo(x)
defined class subImmutableFoo

しかし、数値を追加すると、サブクラスのオブジェクトは取得されません。

scala> (new subImmutableFoo(5)).add(6)
res0: ImmutableFoo = ImmutableFoo@1ee69d3

この問題を解決するためのベスト プラクティスは何ですか?

解決策の 1 つは、サブクラスのメソッドをオーバーライドして、サブクラスのオブジェクトを作成することです。この場合、この解決策は単純ですが、メソッドが大きくなると、多くの二重コード (基本クラス + サブクラス) が発生する可能性があります。または、複数のサブクラスを作成してメソッドをオーバーライドすると、さらに二重のコードになります。

4

2 に答える 2

1

問題としてそれを取るMyType、あなたはこれを行うことができます:

class ImmutableFoo[T <: ImmutableFoo[T] : Manifest](x: Int) {
  def add(y: Int): T = implicitly[Manifest[T]].erasure.getDeclaredConstructor(classOf[Int]).newInstance((x+y).asInstanceOf[Object]).asInstanceOf[T]
}

class SubImmutableFoo(x: Int) extends ImmutableFoo[SubImmutableFoo](x) 

new SubImmutableFoo(2).add(4)

Addableまた、操作の型クラスを定義できますadd。この場合はコードが多すぎますが、このパターンはより一般的です。

trait Addable[T] { 
  def plus(a:T, i:Int):T

  class Infix(x:T) {
    def add(i:Int):T = plus(x, i)
  }
}

class ImmutableFoo(val x:Int)  
class SubImmutableFoo(override val x:Int) extends ImmutableFoo(x)

implicit object AddableFoo extends Addable[ImmutableFoo]{
  override def plus(a:ImmutableFoo, i:Int) = new ImmutableFoo(a.x+i)
}

implicit object AddableSub extends Addable[SubImmutableFoo]{
  override def plus(a:SubImmutableFoo, i:Int) = new SubImmutableFoo(a.x+i)
}

implicit def infix[T: Addable](x:T) = {
  val addable = implicitly[Addable[T]]
  new addable.Infix(x) 
}

new ImmutableFoo(3) add 4  // ImmutableFoo
new SubImmutableFoo(2) add 1 // SubImmutableFoo
于 2012-07-19T10:36:07.903 に答える
1

「MyType」パターンのバリエーションでは、マニフェストまたはリフレクションを使用しない次のことができます。

trait Immu[+Repr <: Immu[Repr]] {
   def x: Int
   def add(y: Int): Repr = newInstance(x + y)
   protected def newInstance(x: Int): Repr
}

class Foo(val x: Int) extends Immu[Foo] {
   def show: String = "Immu(" + x + ")"
   protected def newInstance(x: Int) = new Foo(x)
}

class Bar(x0: Int) extends Foo(x0) with Immu[Bar] {
   def mul(y: Int): Bar = newInstance(x * y)
   override protected def newInstance(x: Int) = new Bar(x)
}

new Foo(3).add(4).show
new Bar(3).add(4).mul(2).show

もちろん、必要なコンストラクター引数の数を変更しないことを前提としています。

于 2012-07-19T11:07:38.623 に答える