「第9回 静的モデル:アソシエーションの基本概念」は、アソシエーションの基本概念とJavaとの関係について説明しました。今回から数回に渡り、UMLアソシエーションを構成する各種部品とJavaとのマッピングについて、具体的に検討していきます。
さて、UMLノーテーション上のアソシエーションは、「アソシエーション」「アソシエーション・エンド」「限定子を示す属性」という3つの部品で構成されていますが、それぞれの部品はさらに、細かい部品の集合となっています。UMLにおけるアソシエーションの部品は、主にアソシエーション・エンドに関連付けられている以下のものです。
第10回では、このうち「可視性(visibility)」まで解説します。
図1(アソシエーション・メタモデル)は、前回説明したアソシエーションのメタモデルです。ノーテーション上のアソシエーションが以下の部品から構成されていることが分かります。
ここでは、ノーテーション上のアソシエーションとメタモデル上のアソシエーションを区別するために、メタモデル上のアソシエーションを「アソシエーション本体」と呼ぶことにします。
また、アソシエーションに関連して、アソシエーションから派生したモデル要素であるアソシエーション・クラスがあります。アソシエーション・クラスはアソシエーションとクラスの両方の性質を併せ持ったモデル要素です。アソシエーション・クラスは後に取り上げる予定です。
アソシエーション本体の部品には以下のものがあります。
アソシエーション名は、アソシエーションそのものの名前です。図1では、アソシエーション(アソシエーション本体)の属性nameとして表現されています。
図1には出てこないアソシエーション本体の部品には、ステレオタイプimplicit、制約xor、タグ付き値persistenceの3つがあります。ステレオタイプimplicitは、暗黙的なアソシエーションであることを示すステレオタイプです。制約xorは、2つ以上のアソシエーション間が排他的に利用されることを示します。タグ付き値persistenceは、アソシエーションが永続化可能であることを示します。
アソシエーション・エンドには、以下のステレオタイプが用意されています。
ステレオタイプassociationは、通常のアソシエーションを示します。デフォルトのステレオタイプであり、ステレオタイプの表示を省略すると自動的にこのステレオタイプということになります。
ステレオタイプglobal、local、parameterは、それぞれグローバル変数、ローカル変数、パラメータに関連付けられたアソシエーションであることを示します。
ステレオタイプselfは、自分自身のオペレーションやアクションを利用するためのアソシエーションであることを示します。
今回は、この中でステレオタイプassociationについて説明します。そのほかのステレオタイプについては次回以降に説明します。
UMLにおけるアソシエーションの部品は、主にアソシエーション・エンドに関連付けられている以下のものです。
この中で、Javaをターゲットにした設計モデルの記述のうえで必須となるのが、ロール名、誘導可能性、可視性、ターゲット・スコープです。また、付加情報として利用することになるのが、集約、多重度、順序付け、変更可能性、インターフェイス指定子、限定子です。以下では、それぞれの部品について説明します。
ロール名は、アソシエーション・エンドに接続された分類子の、アソシエーションにおける役割を示す名前です。アソシエーションの理解で重要なのは、図2に示すとおり、アソシエーションのインスタンスがリンクであるということです。クラスのインスタンスがオブジェクト(インスタンス・オブジェクト)であり、アソシエーションのインスタンスがリンクとなります。
ここで重要なのは、オブジェクトの動的モデルの基本となるメッセージ送受信はこのリンクの上で行われるということです。クラス図でアソシエーションが張られていないところには、オブジェクト図ではリンクが存在することはできないため、メッセージを送受信することができません。つまり、オブジェクト間でメッセージの送受信をするのであれば、クラス図上ではアソシエーションを張っておかなければならないということです。
●2.1.1 UMLでの表現
ロール名は図3に示すように表現されます。
この図はクラスCompanyとクラスPerson間に張られているアソシエーションに対して、クラスPersonはemployeeという役割で参加しているということを意味しています。
●2.1.2 Javaでの実現
UMLのアソシエーションはJava側に直接対応する部品がありません。このため、アソシエーションの持つ意味をJavaでどのように実装するのか、という点が論点となります。アソシエーションの役割のキモとなるのは、メッセージの送受信を行う通信路を確保するということです。Javaにおいてアソシエーションを実現することを考える場合、「オブジェクトAからオブジェクトBのメソッドが呼び出せる」というような条件が満たされればよいということになります。
そして、この目的を達成するためには、「オブジェクトAのインスタンス変数xがオブジェクトBを参照している」ようなインスタンス変数を用いればよいわけです。
こうすることで、オブジェクトAの任意のメソッドの中から、インスタンス変数xを通してオブジェクトBのメソッドを呼び出せます。図3の場合には、以下のようになります。
リスト:ロール名
public class Company { private Person employee; }
クラスCompanyのインスタンス変数employeeにクラスPersonへの参照が格納されているので、クラスCompanyは任意のメソッド内からクラスPersonのメソッドを呼び出すことができます。以上のように、Javaにおけるアソシエーションの実装は、ロール名をインスタンス変数の変数名とするのが基本となります。
●2.1.3 2つのアソシエーション
図4は、Companyクラスから2つのPersonクラスに対してアソシエーションが張られています。
会社のオーナー(Owner)も従業員(Employee)も同じPersonです。どちらのPersonにメッセージを送るのかを、プログラム的にハンドリングできなければなりません。この目的でロール名が利用できます。
図5は、図4のクラス図を具体化(インスタンス化)したオブジェクト図です。CompanyオブジェクトXYZ商事から、この会社の所有者である鈴木さんを示すPersonオブジェクトと従業員である佐藤さんを示すPersonオブジェクトに対してリンクが張られています。そして、個々のリンクに示されているownerやemployeeというロールによってそれぞれのオブジェクトがXYZ商事との間のアソシエーションにおいてどのような役割を持っているかが定義されています。
図6は、図5のオブジェクト図にメッセージを付加し、コラボレーション図にしたものです。XYZ商事から所有者の鈴木さんと従業員の佐藤さんにそれぞれ、メッセージsayHelloが送信されています。
図6で記述されたプログラムは以下のようになります。
リスト:ロール名
public class Company { private Person owner; private Person employee; public void greetingOwner() { owner.sayHello(); } public void greetingEmployee() { employee.sayHello(); } }
メソッドgreetingOwnerは、所有者のsayHelloメソッドを呼び出します。これは図6の“CompanyオブジェクトXYZ商事からPersonオブジェクト鈴木さんにsayHelloメッセージを送信”する処理に対応しています。またメソッドgreetingEmployeeは、所有者のsayHelloメソッドを呼び出します。これは図6の“CompanyオブジェクトXYZ商事からPersonオブジェクト佐藤さんにsayHelloメッセージを送信”する処理に対応しています。
●2.1.4 両端にロール名がある場合
アソシエーションでは、図7に示すようにアソシエーションの両端にロール名がある場合もあります。この例では、クラスCompany側のアソシエーション・エンドにロール名employer、クラスPerson側のアソシエーション・エンドにロール名employeeが付けられています。つまり、このアソシエーションに対してCompanyはemployerという役割で、Personはemployeeという役割で参加しているわけです。
これをJavaで実装する場合には、以下に示すようにクラスCompanyとクラスPersonのそれぞれにインスタンス変数を用います。クラスCompanyにはクラスPersonを参照するインスタンス変数employeeを定義します。これはアソシエーションのロール名employeeに対応します。
リスト:ロール名Company側
public class Company { private Person employee; }
また、クラスPersonにはクラスCompanyを参照するインスタンス変数employerを定義します。これはアソシエーションのロール名employerに対応します。
リスト:ロール名Person側
public class Person { private Company employer; }
以上のように、意味的には1つのアソシエーションであっても、Javaの実装上の都合から2つのクラスにばらばらに実装されることになります。
誘導可能性(isNavigable)は、アソシエーションを通した分類子間の参照の方向を指定します。誘導可能性として指定された方向のみにメッセージを送ることができます。簡単にいうと、アソシエーションの方向と考えてよいでしょう。
●2.2.1 UMLでの表現
誘導可能性は図8に示すように表現されます。アソシエーション・エンドに付けられた矢印によって誘導可能性が表現されます。誘導可能性によって参照の方向が明確になります。この図ではクラスCompanyからクラスPersonの方向に参照が行われている、つまりクラスCompanyからクラスPersonに対してメッセージを送信することができることを示しています。
●2.2.2 Javaでの実現
図8の実装ではクラスCompanyからクラスPersonに対してメッセージ送信、つまりメソッドの呼び出しができればよいわけです。このためには以下に示すように、クラスCompanyのインスタンス変数にクラスPersonへの参照を入れておく方法が普通です。こうすることで、クラスCompanyは好きなタイミングでクラスPersonが公開しているメソッドを呼び出すことができます。
リスト:誘導可能性/Company側
public class Company { private Person employee; }
リスト:誘導可能性/Person側
public class Person { }
●2.2.3 両端に誘導可能性がある場合
図9は、アソシエーションの両端に誘導可能性がある場合です。
この場合は、CompanyとPersonの両側でそれぞれのインスタンス変数を使って、1つのアソシエーションを表現することになります。
可視性(visibility)は、アソシエーション・エンドの公開範囲を指定します。
●2.3.1 UMLでの表現
UMLのノーテーションでは、可視性は図10に示すようにロール名の前の1文字の記号で表現します。
値 | 記号 | 意味 |
---|---|---|
public | + | 公開 |
protected | # | 子孫クラスに公開 |
package | ~ | パッケージ内に公開 |
private | - | 非公開 |
参考 変更可能性 |
4つすべてのシンボルを使った場合は図11のようになります。
●2.3.2 Javaでの実現
可視性はJavaのアクセスコントロールのメカニズムと完全な対応を持っているので、Javaへのマッピングは分かりやすくなっています。図10をJavaで実現すると以下のようになります。
public class Company { private Person employee; }
図11のクラス図に対応するJavaプログラムは以下のようになります。
public class Company { public Person employee1; private Person employee2; protected Person employee3; Person employee4;
図11に対応するJavaプログラムでは、クラスCompanyからクラスPersonに対する4つのアソシエーションにおいて以下のような可視性が指定されています。
ロールemployee1は非公開(記号「-」) |
---|
ロールemployee2は公開(記号「+」) |
ロールemployee3は子孫クラスに公開(記号「#」) |
ロールemployee1はパッケージ内に公開(記号「~」) |
以上の4つの可視性は、下記の表に示すようにJavaのアクセスコントロールの指定に完全にマッピングされます。このマッピングが前述のJavaプログラムでも使用されています。
UML | Java | |
意味 | 記号 | |
非公開 | - | private |
公開 | + | public |
子孫クラスに公開 | # | protected |
パッケージ内に公開 | ~ | 指定なし |
表 可視性の対応 |
以上、「可視性(visibility)」まで説明しました。第11回は、今回に引き続き、アソシエーション・エンドの部品である「ターゲット・スコープ(目標範囲、targetScope)」から順序付け(ordering)」までを解説します。
Copyright © ITmedia, Inc. All Rights Reserved.