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))うん、とってもすっきり。
要するに
デザインパターンも大事だけど、言語側からのサポートがあったほうがハッピーだよね。