あなたはapply()
にNは、引数の数であるために、いくつかのInternableN[Arg1, Arg2, ..., ResultType]
特性を定義することができます。Internable1[A,Z]
、 Internable2[A,B,Z]
などがあります。これらの特性は、キャッシュ自体を定義し、intern()
メソッドとapply
メソッドをハイジャックにします。
InternableN
の特性に実際に適用メソッドがオーバーライドされることを保証するために、特性(または抽象クラス)を定義する必要があります。Applyable
としましょう。
trait Applyable1[A, Z] {
def apply(a: A): Z
}
trait Internable1[A, Z] extends Applyable1[A, Z] {
private[this] val cache = WeakHashMap[(A), Z]()
private[this] def intern(args: (A))(builder: => Z) = {
cache.getOrElse(args, {
val newObj = builder
cache(args) = newObj
newObj
})
}
abstract override def apply(arg: A) = {
println("Internable1: hijacking apply")
intern(arg) { super.apply(arg) }
}
}
クラスのコンパニオンオブジェクトは、InternableN
でApplyableN
を実装する具象クラスのミックスインする必要があります。あなたのコンパニオンオブジェクトに直接定義されたアプリケーションを適用することはできません。
// class with one apply arg
abstract class SomeClassCompanion extends Applyable1[Int, SomeClass] {
def apply(value: Int): SomeClass = {
println("original apply")
new SomeClass(value)
}
}
class SomeClass(val value: Int)
object SomeClass extends SomeClassCompanion with Internable1[Int, SomeClass]
これについての良い点は、元のアプリケーションをインターンに対応するために変更する必要がないことです。インスタンスを作成するだけで、作成する必要がある場合にのみ呼び出されます。
複数の引数を持つクラスに対して、すべてのことを定義することができます。 2つの引数の場合について:
trait Applyable2[A, B, Z] {
def apply(a: A, b: B): Z
}
trait Internable2[A, B, Z] extends Applyable2[A, B, Z] {
private[this] val cache = WeakHashMap[(A, B), Z]()
private[this] def intern(args: (A, B))(builder: => Z) = {
cache.getOrElse(args, {
val newObj = builder
cache(args) = newObj
newObj
})
}
abstract override def apply(a: A, b: B) = {
println("Internable2: hijacking apply")
intern((a, b)) { super.apply(a, b) }
}
}
// class with two apply arg
abstract class AnotherClassCompanion extends Applyable2[String, String, AnotherClass] {
def apply(one: String, two: String): AnotherClass = {
println("original apply")
new AnotherClass(one, two)
}
}
class AnotherClass(val one: String, val two: String)
object AnotherClass extends AnotherClassCompanion with Internable2[String, String, AnotherClass]
相互作用がInternablesはメソッドが必要な場合にのみ実行されます元apply()
前に実行適用されることを示しています。
scala> import SomeClass._
import SomeClass._
scala> SomeClass(1)
Internable1: hijacking apply
original apply
res0: SomeClass = [email protected]
scala> import AnotherClass._
import AnotherClass._
scala> AnotherClass("earthling", "greetings")
Internable2: hijacking apply
original apply
res1: AnotherClass = [email protected]
scala> AnotherClass("earthling", "greetings")
Internable2: hijacking apply
res2: AnotherClass = [email protected]
私は、彼らはもはや他の場所で参照されていたら、インターンキャッシュはインターンインスタンスのガベージコレクションを防止しませんようにのWeakHashMapを使用することにしました。
コードはきちんとご利用いただけますas a Github gist。