私は共通の基本特性の多くのクラスを持っています。これらのクラスのいずれかのインスタンスの新しいインスタンスを作成する必要がある関数がありますが、どちらが実行時にのみ認識されます。
このクラスをパラメーターとして渡し、Scalaで実行時にインスタンスを作成することは可能ですか?
答えが最善のアプローチであるかどうかさえわかりませんが、現在私が考えることができるのはそれだけです。
私は共通の基本特性の多くのクラスを持っています。これらのクラスのいずれかのインスタンスの新しいインスタンスを作成する必要がある関数がありますが、どちらが実行時にのみ認識されます。
このクラスをパラメーターとして渡し、Scalaで実行時にインスタンスを作成することは可能ですか?
答えが最善のアプローチであるかどうかさえわかりませんが、現在私が考えることができるのはそれだけです。
したがって、値を渡すことができます。
myFunc(classOf[myObj])
署名付きのメソッドに
def myFunc(clazz : AnyRef)={ ...
しかし、これは悪臭がします。ファクトリパターンの実装を検討している場合もあれば、ポリモーフィズムを使用して単純に次のことを実行する場合もあります。
myObj.myFunc
あなたの機能はどのクラスが関係しているかに基づいているからです。
Javaの場合と同じ:
classOf[MyClass].newInstance // calls the constructor without parameters
classOf[MyClass].getConstructor(/* parameter types */).newInstance(/* parameters */)
クラスについてはJavadocを参照してください。
これはどのScalaバージョンでも機能します。Scala 2.10には、Scalaの概念を認識する新しいリフレクションライブラリがあります。
テスト不可能なコードやランタイム例外に簡単につながる可能性があるため、リフレクションはできるだけ避けることをお勧めします。
ただし、次のようにそのクラスのビルダーを作成できます。
trait Builder[A]{
def newItem:A
}
次に、適切なビルダーを関数に渡します
def myFunc[A](param1:B,builder:Builder[A])
また、暗黙を活用することもできます
def myFunc[A](param1:B)(implicit builder:Builder[A])
ユースケースをもう少し詳しく説明できるかもしれません。
私は個人的に反省を避けます。
考えられるすべてのユースケースを事前に特定し、識別子を使用してそれらを分類できる場合:
trait SUPER
class A extends SUPER
class B extends SUPER
class C extends SUPER
class D extends SUPER
val idA = 'CLASS_A
val idB = 'CLASS_B
val idC = 'CLASS_C
val idD = 'CLASS_D
def build(selectedId: Symbol): SUPER = selectedId match {
case 'CLASS_A => new A
case 'CLASS_B => new B
case 'CLASS_C => new C
case 'CLASS_D => new D
}
そうでなければ、ビルダーを好むなら、私は@Edmondo1984のアドバイスに従うでしょう
必要なものを取得するための最も「シームレスな」方法は、インスタンス化を行うメソッドを、コンテキストがバインドされた型パラメーターを持つものとして宣言することです。ClassManifest
def maker[T : ClassManifest](args...): T = ...
これにより、コンパイラは自動的にのインスタンスClassManifest[T]
をmakerに渡します。呼び出し元は、インスタンス化する特定のクラスを指定するだけで済みます。
package rrs.scribble
import scala.reflect.ClassManifest
object Maker
{
def maker[T : ClassManifest]: T = {
val cmT = implicitly[ClassManifest[T]]
val cT = cmT.runtimeClass
cT.newInstance.asInstanceOf[T]
}
}
これは、問題のクラスに引数なしのコンストラクターがある場合にのみ機能します。引数を使用してコンストラクターを呼び出すことができますが、それははるかに複雑です。JavaリフレクションAPIに精通している必要があります。
REPLでは:
scala> import rrs.scribble.Maker._
import rrs.scribble.Maker._
scala> class Argless
defined class Argless
scala> val s1 = maker[Argless]
s1: Argless = Argless@1512d075