職場実習18日目

今日もGrails作業

作者ドメインと作品ドメインが出来上がったので、次はグループドメイン作りに挑戦。

グループドメイン改めカテゴリードメイン

しかし、ドメイン管理にSQLを使ってるせいか、グループ(group)という名前ではSQL予約語と被ってしまい、エラーが続出したため、名前をカテゴリー(category)に変更。

カテゴリードメイン入れ子構造を作る

次に、カテゴリードメインに階層属性と親カテゴリー属性を持たせ、階層の高いカテゴリーが低いカテゴリーを包含するツリー構造を作る。階層属性は、ある程度の拡張性を持たせるため、階層名と階層の高さを持つ「階層」ドメインで定義する。(作品はツリー構造の最下部に位置するため、カテゴリードメインのサブクラスにする。)
そのためには、親カテゴリーを決める際の制約として、自分の階層より高い階層を持つカテゴリーのみ指定できるという条件を付ける必要がある。しかし、constraintsで指定できる条件の中に、そのようなものは含まれていないため、validatorでクロージャーを作るしか方法が見付からなかった。

そして、作ってはみたものの、エラーが出てコンパイルが通らず、原因が分からなかったので、一旦条件を外してコンパイルしてみたら、実行できた。
条件が無いため、例えばカテゴリー「ジャンル」をカテゴリー「シリーズ」のサブカテゴリーにしたり、作品のサブカテゴリーに「ジャンル」を位置付けるという変な事までできてしまう。
とりあえず、このままでは実用に適さないため、次の方法を考える。

カテゴリーを具体的なものに分ける

カテゴリードメインの中に、階層属性を持たせるのではなく、ジャンルやシリーズと言った階層そのものをドメインにして、ジャンルはシリーズのみを包含し、シリーズは作品のみを包含するというstrictなツリー構造とする。
この方法なら、階層の高さを使って検査制約を作る必要がなくなる。
ただし、欠点はある。作品をカテゴリーに含めようとしたら、必ずシリーズに含めなければならない。シリーズ化しない単体の作品をジャンルに直接含める事ができないのだ。
これでは不便なので、ジャンルとシリーズ、またはシリーズと作品、あるいはそれら全てを一括りにできる方法を考える。

カテゴリーインターフェースを、各カテゴリーに実装する

カテゴリーを括るためだけのインターフェース(Javaファイル)を作り、それをジャンル、シリーズ、作品に実装する事で、これらをカテゴリーとして扱う事ができる。さらに、カテゴリーのサブインターフェースとして、親カテゴリーと子カテゴリーインターフェースを作り、ジャンルは親カテゴリー、シリーズは親カテゴリーと子カテゴリーの両方、作品は子カテゴリーのみを実装し、作品は親カテゴリー(ジャンルかシリーズのいずれか)に包含され、ジャンルは子カテゴリー(シリーズか作品のいずれか)を包含するので、作品を直接ジャンルに含める事もできる。
ただし、シリーズをシリーズに含めるのを防ぐための制約条件が必要となるので、この方法では完全とは言えない。しかも、このカテゴリーインターフェースの型をドメインの中で扱うとコンパイルエラーが起こるため、複数のドメインを括るという本来の目的に使えず、あえなく頓挫。

インターフェースを使わず、カテゴリーの階層構造を厳密に定義する

単純に、作品をシリーズとジャンルのどちらにでも含められるようにし、シリーズをジャンルに含められるようにする実装が一番簡単だった。ただし、作品はシリーズとジャンルの両方に含められるし、ジャンルとシリーズが親子関係にある必要は無い。これではまだ実用には程遠い。どちらか片方にしか含められないようにする条件を考えなければ。