Value Object とは、ビジネスロジックで管理する対象ではない、単なる値でしかないオブジェクトです。
Identity Map はエンティティの重複を避けるパターンでした。プログラムで扱うものに対して、重複したインスタンスが存在すると、矛盾した状態が生まれてしまい、問題になります。Value Object はそうした一意性の問題とは無関係な、いくら重複しても問題にならない小さなオブジェクトです。Value Object の決定的な特徴は、一意性がなく、等価性が重要である点です。
C++ や Java のようなパフォーマンスを重視する言語には、オブジェクト型でないプリミティブ値があります。通常、単純な数値はこのプリミティブを使って表現します。けれど、日付や分数などは、要素となるバラバラの数値で扱うのではなく、複合的な値の組み合わせにしたほうが扱いやすくなります。オブジェクトの形を取っているけれど、プリミティブ値のように、意味さえあっていればいいのでインスタンスの管理は不要 (とくに Java のように優れた GC を持つ言語では) と言えるオブジェクトが Value Object です。
Value Object は、変化する状態を持たないイミュータブルなオブジェクトにできるなら、積極的にそうしたほうが有利です。もし意図せずインスタンスを共有していたら、中身が書きかわってしまわないと保証できません。Java や Python は、最適化によって内容が同じ文字列オブジェクトを共有します。これは String がイミュータブルだから可能な方法です。
だかといって、不変にすることが必要条件というわけでもありません。たとえば Query Object のクライテリアは Value Object です。Query Object のコンポジットに追加的に条件を入れたくなったとき、すべて再構築しないといけないのは厳しすぎます。そもそも、クエリの大枠の原型に add()
して作っていくことができず、末端から積み上げないと構築できないのは、ビルダーとして不便すぎますね。
Money は Value Object の代表格です。業務プログラミングは金額を扱うことが多々あります。金額を生のプリミティブ値で管理するのは、インターネット時代のプログラムとしては少々不出来です。なぜなら、オンラインのビジネスは国境を超えやすいのがメリットで、それを活かすには、為替レートの異なる通貨での決済が不可欠だからです。同じ国の中でも、発行者が異なる各種電子マネーでのトレードも活発になりました。
数値だけを見て単純に足し算してはいけないお金が数多くあります。コンピューターはそんな事情を知らないので、数字でありさえすれば、言われたとおり演算してしまいます。お金の扱いでのうっかりミスは、大事故になります。それぞれのビジネスには、お金の扱いに関する制約が必要なので、それをモデリングするのに、お金タイプの Value Object を活かす Money パターンが有効です。
Special Case は、オブジェクトの多態性を活かして、特別なデータの場合に、同じ抽象クラスを共有する異なる具象クラスのインスタンスを生成し、透過的に扱えるようにするパターンです。
Value Object における Special Case の代表は Null Object です。null の可能性を考慮し忘れてオブジェクトのメソッドを呼び出すと、あの有名なヌルポ (NullPointerException) が発生します。扱う Value Object の型と同じ型の派生で null を意味するバージョンを設け、それを使うようにすることで、そのままメソッドを呼び出すように記述することができます。通常は何らかの処理が実行されるけれど、その特殊ケースとして、何も起きないという処理になります。
Single Table Inheritance はエンティティの Special Case を実現するのに最適です。無効レコードも特別扱いレコードも、多態性で振る舞いの変化をあらかじめ作っておけるので、扱う方は何も考えず、同じメソッドコールをするだけで済みます。
追記
ベースパターンには他に、Gateway、Mapper、Layer Supertype、Record Set が紹介されています。先に登場した各パータンにすでに含まれている語彙ばかりです。業務 Web アプリケーションに限らず、基礎をおさえる意味で、最後に補足的に説明されています。
ちょっとそのままではないのが Layer Supertype ですが、これは「Service Layer の一般化」のことです。Domain Model のファサードとなるサービスに、再利用可能な共通した機構を設けておき、横断的な関心の扱いが機能によって違うといった一貫性のなさを排除するのに利用できます。Implicit Lock のような仕組みに活用できるでしょう。