2

トレイトの実装を生成するメソッドを作成したいと思います。例えば:

trait Foo {
  def a
  def b(i:Int):String
}

object Processor {
  def exec(instance: AnyRef, method: String, params: AnyRef*) = {
    //whatever
  }
}

class Bar {
  def wrap[T] = {
    // Here create a new instance of the implementing class, i.e. if T is Foo,
    // generate a new FooImpl(this)
  }
}

次のように動的にFooImplクラスを生成したいと思います。

class FooImpl(val wrapped:AnyRef) extends Foo {
  def a = Processor.exec(wrapped, "a")
  def b(i:Int) = Processor.exec(wrapped, "b", i)
}

それぞれの特性を手動で実装することは私たちが望んでいることではないので(多くの定型文)、コンパイル時にImplクラスを生成できるようにしたいと思います。クラスに注釈を付けたり、コンパイラプラグインを作成したりすることを考えていましたが、もっと簡単な方法があるのではないでしょうか。任意のポインタをいただければ幸いです。

4

3 に答える 3

2

java.lang.reflect.Proxyあなたが望むことに非常に近い何かをすることができます:

import java.lang.reflect.{InvocationHandler, Method, Proxy}

class Bar {
  def wrap[T : ClassManifest] : T = { 
    val theClass = classManifest[T].erasure.asInstanceOf[Class[T]]
    theClass.cast(
      Proxy.newProxyInstance(
        theClass.getClassLoader(), 
        Array(theClass), 
        new InvocationHandler {
          def invoke(target: AnyRef, method: Method, params: Array[AnyRef])
            = Processor.exec(this, method.getName, params: _*)
        }))
    }
  }

これで、を生成する必要はありませんFooImpl

制限は、メソッドが実装されていないトレイトに対してのみ機能することです。より正確には、メソッドがトレイトに実装されている場合、それを呼び出すとプロセッサにルーティングされ、実装は無視されます。

于 2012-08-04T18:10:54.497 に答える
1

ScalaMockでこれを行う3つの異なる方法を見ることができます。

ScalaMock 2(Scala 2.8.xおよび2.9.xをサポートする現在のリリースバージョン)はjava.lang.reflect.Proxy、動的に型付けされたモックと静的に型付けされたモックを生成するコンパイラプラグインをサポートするために使用します。

ScalaMock 3(現在Scala 2.10.xのプレビューリリースとして利用可能)は、マクロを使用して静的に型付けされたモックをサポートします。

Scala 2.10.xを使用できると仮定すると、コンパイラプラグインよりもマクロベースのアプローチを強くお勧めします。(ScalaMockが示すように)コンパイラプラグインを確実に機能させることはできますが、それは簡単ではなく、マクロは劇的に優れたアプローチです。

于 2012-08-05T10:04:49.877 に答える