私は現在scalaを発見していて、ファクトリでトレイトを使用できるかどうか疑問に思っていました。
私はこれを試しました:
抽象クラスFoo{ ..。 } オブジェクトFoo{ def apply()= new Bar プライベートクラスのバーはFooを拡張します{ ..。 } } MyTraitを使用したFoo()//機能しない
with
の前に。が必要なためだと思いnew
ます。
それで、これを行う方法はありますか?
ありがとうございました
いいえ、手遅れです。apply()メソッドが戻ったときにインスタンスはすでに作成されています。
できることは、ファクトリメソッド内の特性を使用することです。以下のコードは、私が書いているかなり大きなコード例からのものです。
object Avatar {
// Avatar factory method
def apply(name: String, race: RaceType.Value, character: CharacterType.Value
): Avatar = {
race match {
case RaceType.Dwarf => {
character match {
case CharacterType.Thief => new Avatar(name) with Dwarf with Thief
case CharacterType.Warrior => new Avatar(name) with Dwarf with Warrior
case CharacterType.Wizard => new Avatar(name) with Dwarf with Wizard
}
}
case RaceType.Elf => {
character match {
case CharacterType.Thief => new Avatar(name) with Elf with Thief
case CharacterType.Warrior => new Avatar(name) with Elf with Warrior
case CharacterType.Wizard => new Avatar(name) with Elf with Wizard
}
}
}
}
}
class Avatar(val name: String) extends Character {
...
}
このコードでは、アバターのタイプ(職業と人種)は、RaceTypeとCharacterTypeの列挙に基づいて工場で決定されます。あなたが持っているのは、あらゆる種類の異なるタイプまたはタイプの組み合わせのための 1つのファクトリです。
あなたが持っていると言う:
class Foo
object Foo { def apply() = new Foo }
trait Baz
それで:
Foo() with Baz
次のようになります。
val foo = new Foo
foo with Baz
これは、Scalaにはない、ある種のプロトタイプベースの継承を意味します。(私の知る限りでは。)
(思考の誤りは、直観的に=記号を「置換記号」と間違えていると思います。つまり、Foo()はFoo.apply()を意味し、新しいFooと「等しい」ので、Foo()を新しいFooに置き換えることができます。 。明らかにできません。)
暗黙の変換によるソリューション
ケンは、この場合、プロキシが私たちを助けることができると提案しました。ここでやろうとしているのは、インスタンスの作成後にトレイトをインスタンスに追加することです。この「モンキーパッチ」は、他の誰かがクラス(およびapply()
メソッド)を作成し、ソースにアクセスできない場合に役立つ可能性があります。この場合、暗黙の変換によってインスタンスの上にプロキシ/ラッパーを追加することができます(手動変換は必要ありません)。
例を使用すると、次のFoo
ように実行できます。
class Foo
object Foo { def apply() = new Foo }
trait Baz { def usefulMethod(s: String) = "I am really useful, "+ s }
// ---- Proxy/Wrapper ----
class FooWithBazProxy extends Foo with Baz
// --- Implicit conversion ---
implicit def foo2FooWithBazProxy(foo: Foo): FooWithBazProxy = new FooWithBazProxy
// --- Dummy testcode ---
val foo = Foo()
println(foo.usefulMethod("not!"))
出力:
I am really useful, not!
この例が気に入らない理由は次のとおりです。
Baz
使用しませんFoo
。にを付けたい理由がわかりにくいusefulMethod()
ですFoo
。
そこで、インスタンスに「モンキーパッチ」を適用したトレイトが実際にインスタンスを使用する新しい例を作成しました。
// --------- Predefined types -----------
trait Race {
def getName: String
}
class Avatar(val name: String) extends Race{
override def getName = name
}
object Avatar{
def apply() = new Avatar("Xerxes")
}
// ---------- Your new trait -----------
trait Elf extends Race {
def whoAmI = "I am "+ getName + ", the Elf. "
}
// ---- Proxy/Wrapper ----
class AvatarElfProxy(override val name: String) extends Avatar(name) with Elf
// ---- Implicit conversion ----
implicit def avatar2AvatarElfProxy(Avatar: Avatar): AvatarElfProxy = new AvatarElfProxy(Avatar.name)
// --- Dummy testcode ---
val xerxes= Avatar()
println(xerxes.whoAmI)
プリント:
I am Xerxes, the Elf.
この例では、追加されたElf
トレイトは、getName
それが拡張するインスタンスのメソッドを使用します。
エラーが表示された場合はありがたいですが、私は暗黙的ではありません(まだ)。
プロキシと暗黙の変換を使用したソリューション
この例では、olleのソリューションを拡張して、ユーザーがapply()
メソッドを呼び出すときにミックスイン特性を指定できるようにします(例val xerxes = Avatar[Elf]("Xerxes")
)。
// ----- Predefined types -----
trait Race {
def whoAmI: String
}
class Avatar[R <: Race](val name: String)
object Avatar {
def apply[R <: Race](name: String) = new Avatar[R](name)
}
// ----- Generic proxy -----
class AvatarProxy[R <: Race](val avatar: Avatar[R])
implicit def proxy2Avatar[R <: Race](proxy: AvatarProxy[R]): Avatar[R] =
proxy.avatar
// ----- A new trait -----
trait Elf extends Race {
self: AvatarProxy[Elf] =>
def whoAmI = "I am " + self.name + ", the Elf."
}
implicit def avatar2Elf(avatar: Avatar[Elf]): AvatarProxy[Elf] with Elf =
new AvatarProxy[Elf](avatar) with Elf
// --- Test code -----
val xerxes = Avatar[Elf]("Xerxes")
println(xerxes.whoAmI)
プリント:
私はエルフのクセルクセスです。