ScalaでCompositeパターン
30分プログラム、その448。Scalaのcase classを使って、Compositeパターンを作ってみる。
ディレクトリみたいなツリー状になっているデータ構造を表現するのに、とっても便利なCompositeパターンをScalaで書いてみよう。
まずは普通に定義しよう。
まずは、増補改訂版Java言語で学ぶデザインパターン入門に載っているコードを、そのままScalaに移してみよう。ただ、全部マネすると大変なので、機能をサイズ取得だけにしぼる。
UMLにするとこんな感じ。
abstract class Entry{ def size : int } class File(n : int) extends Entry{ def size : int = n } class Directory extends Entry{ import scala.collection.mutable.ListBuffer private val directory = new ListBuffer[Entry] def size : int = { directory.foldLeft(0)(_ + _.size) } def add(e : Entry) : Unit = { directory += e } } val root = new Directory val bin = new Directory bin.add(new File(100)) bin.add(new File(200)) root.add(bin) println(root.size)
case classを使って書き直す
さて、Scalaにはcase classというステキな機能がある。これは
- ファクトリメソッドが自動で生成される(new不要)
- パラメータがvalでえ宣言したのと同じに扱われる。(getterの自動生成)
- toString/hashcodeが自動で生成される
- パターンマッチができる
みたいなやつ。
これを使ってCompositeパターンを定義しなおしてみよう。
sealed abstract class Entry case class File(size : int) extends Entry case class Directory(directory : List[Entry]) extends Entry def size(entry : Entry) : int = { entry match { case Directory(directory) => directory.foldLeft(0)(_ + size(_)) case File(size : int) => size } } val bin = Directory(List(File(100),File(200))) val root = Directory(List(bin)) println(size(root))
うん、とってもすっきり。
要するに
デザインパターンも大事だけど、言語側からのサポートがあったほうがハッピーだよね。