 |
使えるUML 第11回 |
2007.12.6 掲載
大人のオブジェクト指向 〜契約による設計〜(最終回)
3年間という長いようで短いような間、お付き合い頂いた本コラムも、一旦今回が最終回となります。今までご愛読下さったみなさん、大変ありがとうございました! 最後はオブジェクト指向の原点のひとつとも言うべき「契約による設計(DbC:Design by Contract)」についてです。
大人の世界は契約がいっぱいです。部屋やお金を借りるときはもちろんのこと、企業活動を行う上では必ず契約が登場します。システムの世界もこれに似て、大人なオブジェクト指向システムではオブジェクト間の契約が重要になります。
◇契約による設計
「契約による設計(DbC:Design by Contract)」とは、バートランド・メイヤー(Bertrand Meyer)氏が提唱したオブジェクトのインタフェースを厳密に定義するための方法です。オブジェクトとそれを使用するオブジェクトがそれぞれ守るべきことを記述することから、「契約」というメタファ(比喩)を当てはめています。UMLで登場する操作のシグニチャ(操作名や引数の型など)も広い意味では契約の一種になりますが、OCLを利用して「契約による設計」を行うことで、オブジェクトの仕様からあいまいさを排除できます。
◇契約(守る条件と守ってもらう条件)
オブジェクト指向システムでは、オブジェクトが他のオブジェクトの操作を呼び出し、互いにメッセージをやりとりしながら処理が行われます。このとき、サービスを受けたい側が操作を呼び出すときに守るべき条件を「事前条件(precondition)」と呼び、サービスを提供する側が呼び出された後に守るべき条件を「事後条件(postcondition)」と呼びます。また、サービスを提供する側が常に満たすべき条件を「不変条件(class invariant)」と呼びます。契約による設計は、この「事前条件」と「事後条件」および「不変条件」の3つで成り立っています。
| 条件 |
意味 |
確認のタイミング |
事前条件 (precondition) |
操作呼び出し時の引数が満たすべき条件 |
操作呼び出し前 |
事後条件 (postcondition) |
操作による処理が終了した時点で満たすべき条件 |
操作呼び出し後 |
不変条件 (class invariant) |
オブジェクトが常に満たすべき条件 |
コンストラクタや操作の呼び出し前後 (ただし、操作の実行中には守られなくてもよい) |
表1 オブジェクト間の契約における条件
◇演劇予約システムの例
前回と同様に、演劇を予約するためのシステムを例にして説明していきます。
図1 演劇予約システムのクラス図
「公演」クラスを中心に見てみると、公演が行われる「劇場」が「公演会場」として関連しており、この劇場によって座席数が決定します。また、公演は「予約」を通して「顧客」と関連しています。当然のことながら、ある公演に対するすべての予約の座席数合計が、公演会場の座席数を超えてはいけません。これは、常に満たされるべき条件なので、不変条件として表現します。
context 公演 inv: self.予約->sum(座席数) <= self.公演会場.座席数 |
余談ですが、不変条件の確認は、コンストラクタが終了した後に始まることから、「コンストラクタとは、クラスの不変条件を満たすようにオブジェクトを初期化するところ」ととらえることができます。別の言い方をすると、不変条件によって、コンストラクタで行うべきことを示唆するということでもあります。演劇予約システムの例では、不変条件内で公演会場が登場するので、公演クラスのコンストラクタでは「公演会場」を初期化するべきであることが分かります。
◇公演を「予約する」際の約束事
「公演」クラスには「予約する(予約希望者, 予約席数)」操作があります。この操作では「予約」を作成し、操作の呼び出し元に返すものとします。この操作の事前条件と事後条件を記述してみましょう。
図2 「予約する」操作の事前/事後条件
| 番号 |
説明 |
| (1) |
pre:は、その後に続く式が事前条件であることを表します。 |
| (2) |
OCLIsUndefined()は、OCLAny(OCL内すべての型のスーパータイプと考えることができる型)に定義されている演算です。値が未定義かどうかを判定します。JavaやC#などを使用したことがある方はnullかどうかをチェックするものだと思えば良いでしょう。OCLAnyに定義されている演算は、必ずOCLの接頭辞で始まります。 |
| (3) |
予約の座席数は1より大きくなければならないことを表します。 |
| (4) |
post:は、その後に続く式が事後条件であることを表します。事後条件では、後の例で見るように@preや^などの特殊な演算を使用することで複雑な条件を記述することができます。 |
| (5) |
「result」は、操作の結果を表すOCLの予約語です。 |
| (6) |
OCLIsNew()もまたOCLAnyで定義された演算です。操作の最中に作成されたオブジェクトかどうかを判定します。 |
| (7) |
予約@preなどのように項目名の後に@preを記述することで、操作が始まる前の値を表すことができます。 |
| (8) |
->including()はコレクション演算の一種で、引数の要素を追加したSetを表します。式全体として、操作終了後の予約Setは、操作開始前の予約のSetにresultを追加したものと等しいことを表します。 |
| (9) |
「^」は操作中にメッセージを送ったことを表します。操作中に予約希望者にポイントを加算する(result)のメッセージを送っていることを表します。 |
表2 「予約する」操作の制約の説明
◇まとめ
今回は、OCLによってオブジェクト間の契約を定義する方法を見てきました。実際のプロジェクトでは、どの程度詳細に記述するのかや、OCLではなく日本語(自然言語)を利用するなど、チームにとって最適な方法を選択できます(「無理のない開発計画を」)。また、アクティビティ図に標準で用意されている≪precondition≫、≪postcondition≫といったキーワードや、シーケンス図の「状態不変表明(StateInvariant)」を利用するのも良いでしょう。
冒頭でも書かせていただきましたが、今回が、3年間続けさせていただいたコラムの締めくくりになります。UMLは簡単に利用できるというだけではなく、UMLを利用したモデリングは奥が深く、有効的な使い方が尽きることはありません。本コラムに含めることができなかった使い方については、別の機会に紹介させていただければ幸いです。それでは、またどこかでお会いできることを楽しみにしております。ご愛読大変ありがとうございました。
◇書籍紹介
「契約による設計」という考え方は、CBD(コンポーネントベース開発)モデリングでのインタフェース定義や、TDD(テスト駆動型開発)でのユニットテスト、Eclipseプラグインのマニフェストなど、いくつかの実践的な技術に応用されています。これらの詳細につきましては、弊社テクノロジックアートが翻訳に関わりました以下の書籍をご参照ください。
 |
ビジネスコンポーネントファクトリ 〜エンタープライズ領域でのコンポーネント指向開発〜 |
【共著】 Peter Herzum, Oliver Sims
【翻訳】 有限会社トップスタジオ
【監訳】 長瀬 嘉秀
【出版】 株式会社翔泳社
【ISBN】 4-79810-093-5
|
 |
XPエクストリーム・プログラミング入門 〜変化を受け入れる 第2版〜 |
【共著】 Kent Beck
【翻訳】 株式会社テクノロジックアート
【監訳】 長瀬 嘉秀
【出版】 株式会社ピアソン・エデュケーション
【ISBN】 4-89471-685-2
|
 |
Eclipseクックブック |
【共著】 Steve Holzner
【翻訳】 株式会社テクノロジックアート
【監訳】 長瀬 嘉秀
【出版】 株式会社オライリー・ジャパン
【ISBN】 4-87311-208-7
|
また、UMLに関する詳細につきましては、同じく弊社テクノロジックアートで提供しておりますトレーニングコースや、コンサルティングサービスをご活用いただけます。
■筆者紹介
照井 康真/Koma Terui
山下 智也/Tomonari Yamashita 株式会社テクノロジックアート テクニカルデプト UMLモデリンググループ
|