自分型アノテーション
自分型アノテーションの用途は二つある。
- thisの別名を定義する。
- クラスの機能を分割する。
thisの別名を定義する
object SelfTypeAnnotationSample1 { self => // 自分型アノテーション。=>の右側には何もない。「class Internal」を指しているわけでもない。 class Internal { def procedure = { SelfTypeAnnotationSample1.this.procedure self.procedure } } def procedure = { println("hello world") } def main(args: Array[String]) { new Internal().procedure } }
この結果は
hello world hello world
クラスの機能を分割する
一つのクラスの機能を複数のクラスに分割する場合、Javaでは一般に集約を行うが(継承はだめ)、Scalaではtraitによるミックスインという方法がある。 しかし、ミックスインでは機能を集約できるものの、その機能が外側から見えてしまう。
他のtraitの機能をターゲットのクラスにミックスインしつつ、そのtraitの存在を外部に教えないようにするために、自分型アノテーションを使うことができる(こういう説明でよいかわからない)。
以下では、SampleはSomeOtherを自分型として指定するが、これは抽象traitである。 Sampleのオブジェクト生成時に実装traitを指定する。
Sampleを使う側は、このオブジェクトがSomeOtherを利用していることは知らないし、そのメソッドにもアクセスすることはできない。
trait SomeOther { def something } trait SomeOtherImpl extends SomeOther { def something = { println("something") } } class Sample { self: SomeOther => def test = { something } } object SelfTypeAnnotationSample2 { def main(args: Array[String]) { object SampleImpl extends Sample with SomeOtherImpl; SampleImpl.test } }
この手法は「Cakeパターン」と呼ばれるDI手法と言われることがあるのだが、新たなパターンというよりも、「手によるコンストラクタ注入」の代用と言った方がよい。