以前に、パラレル継承階層を実装するとダウンキャストが避けられないとの記事を書きました。
またTypeScript
を使うとある程度対応できる記事を書きました。
そして、ダウンキャストをなくすためには下記の2つの機能が言語に必要となりますが、Scala
にはその機能があることがわかりました。
- 継承可能な型引数をサポートすること
- ジェネリックワイルドカードをサポートすること
Scalaを利用すれば完全に対応できることがわかりました。
中身と入れ物の関係がパラレル継承階層になりがちなので、TypeScriptと同じ例を下記に示しました。
中身は BaseContent⇒DerivedContent⇒DerivedContent2 と継承します。一方、入れ物はこれに対応して、BaseBox⇒DerivedBox⇒DerivedBox2 と継承します。
BaseBoxは中身を参照するcontentプロパティを持ち、これをTContent型としています。入れ物の継承に従ってこの型引数も制約の型をより継承した中身の型へと変えていきます。このようにすることで、contentへの代入は型安全が保たれます。また、サンプルプログラムでは省略していますが、各入れ物クラスの中でcontentのハンドリングの際にダウンキャストは発生しません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class BaseContent { }
class BaseBox { type TContent <: BaseContent var content: Option[TContent] = None }
class DerivedContent extends BaseContent { val prop1 = 0 }
class DerivedBox extends BaseBox { override type TContent <: DerivedContent }
class DerivedContent2 extends DerivedContent { val prop2 = 0 }
class DerivedBox2 extends DerivedBox { override type TContent = DerivedContent2 }
object ParallelInheritance { def main(args: Array[String]) = { val derivedBox = new DerivedBox() val derivedBox2 = new DerivedBox2() val baseBox: BaseBox = derivedBox2 println(derivedBox2.content.get.prop1) derivedBox2.content = Some(new DerivedContent2()) } }
|