クラス図は、シーケンス図と組み合わせて使用することで、非常に効果的なコミュニケーションメカニズムを提供します。クラス図ではクラス間の関係性を示すことができ、シーケンス図ではこれらのクラスのインスタンス間で送信されるメッセージとその順序を示すことができます。あるオブジェクトが別のオブジェクトにメッセージを送信する場合、2つのクラス間には関係性があり、その関係性はクラス図に表示する必要があります。
統一モデリング言語(UML)を構成する要素の多くは、Javaプログラミング言語に正確にマッピングされています。そこで、Javaの標準的なイベント処理メカニズムをシミュレートするUMLの例を見ることで、クラス図とシーケンス図がどのように相互に補完し合うかを示すことができます。Javaアプリケーションを開発する際には、この例に似たパターンを使用してアプリケーション内のイベントを処理することが非常に一般的です。
シーケンス図図A
では、EventExampleオブジェクトがTimeEventSourceオブジェクトにメッセージを送信しています。このメッセージにより、addTimeChangeListener()メソッドがトリガーされます。オブジェクト間で送信されるメッセージの順序は常に上から下、通常は左から右へと読みます。図Aでは、理解を深めるために注釈が付けられています。
図A |
![]() |
シーケンス図 |
シーケンス図をさらに詳しく見ていきましょう。図中の番号はそれぞれ以下の通りです。
- EventExample(システム内の任意のオブジェクト)は、TimeChangeListenerオブジェクトを作成することでイベントシミュレーションを開始します。当然ですが、インターフェースのインスタンスを持つことはできません。ただし、TimeEventSourceはTimeChangeListenerの実装ではなく、リスナー自体に結合されていることを明確にしておくことが重要です。
- EventExample オブジェクトは、TimeChangeListener を TimeEventSource オブジェクトに登録するようになりました。
- EventExample 呼び出しは TimeEventSource で開始され、登録されているリスナーにイベントの送信を開始します。
- TimeEventSource は、このイベントに関する情報をカプセル化する TimeChangeEvent オブジェクトを作成します。
- TimeEventSource は各リスナーをループし、各リスナーに対して timeChange メソッドを呼び出します。
- オプションとして、TimeChangeListener はイベント通知の原因となったオブジェクトへの参照を取得できます。この参照は、java.lang.Object への汎用参照として返されます。
- TimeChangeListener は、イベントの処理を処理するために processEvent() メソッドを呼び出します。
TimeChangeListenerインターフェースに注釈を付けて、このインターフェースを実装するクラスを実際に作成することを指定していることに気付くでしょう。この注釈により、TimeChangeListenerの代わりにどのクラスを使用しても、メッセージシーケンス全体が維持されるため、図の柔軟性が大幅に向上します。また、TimeEventSourceオブジェクトがリスナーに時刻変更を通知する際に、複数のリスナーに通知してループが発生する可能性があることも注釈で指定しておくとよいでしょう。
重要なのは、この図を解釈し、コード構築に活用する必要がある開発者が、効果的に作業を行うためには、注釈に記載されている情報を把握しておく必要があるということです。注釈は、一連のイベントに関連する詳細をより深く理解するのに非常に役立ちます。注釈はほとんどの図に表示されるべきです。クラス図は様々な方法で相互作用するため、通常、1つのクラス図には複数のシーケンス図が必要です。シーケンス図の目的は、クラス図が相互作用する一つの方法をモデル化することです。
クラス図図B
のクラス図は、Javaイベントシミュレーションの構造的表現です。この図に表示されている各関係に注目してください。まず、EventExampleクラスはTimeEventSourceおよびTimePrinterと関係があり、これはEventExampleオブジェクトがこれらのクラスのインスタンスに送信するメッセージに対応しています。
図B |
![]() |
クラス図 |
図Aのシーケンス図にはTimePrinterオブジェクトが含まれていませんでした。実際にはTimePrinterが含まれていましたが、TimeChangeListenerインターフェースの形で含まれていました。図Bに示すように、TimePrinterはTimeChangeListenerインターフェースを実装しています。また、この図には、シーケンス図では明らかにされていなかった構造的な継承関係が描かれていることにも注目してください。
図を解釈する際には、クラス図とシーケンス図を並べて配置するのが最も簡単です。まずシーケンス図を読み進め、オブジェクト間でメッセージがやり取りされる様子を、クラス図上の関係性へと遡って確認してみましょう。そうすることで、クラス図上の関係性が存在する理由を理解するのに役立ちます。シーケンス図を読んだ後、クラス図上でメソッド呼び出しにマッピングできない関係性を見つけた場合は、その関係性の妥当性について疑問を持つべきです。
パッケージ図
パッケージ図はクラス図の一種です。クラス図との違いは、パッケージ図が個々のパッケージ間の関係を示すことです。パッケージ図は、システムの高レベルなビューと考えることができます。これは、システムのアーキテクチャを理解する上で重要になります。図C に示されている依存関係は、様々なパッケージ内のクラス間の構造的関係の方向を示しています。
図C |
![]() |
パッケージ図 |
ご覧のとおり、eventhandling パッケージは util パッケージに依存しています。つまり、eventhandling 内のクラスは util 内のクラスをインポートできますが、その逆はできません。これは重要な区別です。パッケージの依存関係は、対応するクラス図で表現された関係と一致している必要があるためです。
パッケージ図は、クラス図と組み合わせることで、システムのアーキテクチャを伝える効果的な手段となります。図Cのような図は、システム全体の構造を高レベルで概観することができます。これにより、開発者は個々のクラス間の関係性について推測を立てることができます。これは、新しい開発者がプロジェクトに参加し、すぐに慣れる必要がある場合や、以前作業したことがあるもののしばらく操作していないシステムを保守する必要がある場合などに特に役立ちます。
いずれにせよ、この形式の建築モデリングは有益です。この例のコードは、JOUPオンラインの付録Cからダウンロードできます。
慎重な解釈
ご覧のとおり、UMLの多くの要素はJavaプログラミング言語に正確にマッピングされており、これはUMLが正確かつ明確なコミュニケーションメカニズムであるという主張と一致しています。開発者として、私たちはこれらの要素をこの主張に忠実に解釈する必要があります。これらの要素の解釈が異なると、誤解が生じる可能性があり、まさにUMLが解決しようとしている課題です。
UMLは正確ですが、図が実際に伝える以上の意味を引き出さないように注意する必要があります。UMLはビジュアルプログラミング言語ではなく、モデリング言語です。したがって、コードと同じ詳細レベルでモデリングすることを意図しているわけではありません。図は通常、何かを実装する方法を記述するのではなく、特定のニーズに対応する必要があることを伝えるだけです。