「第10回 静的モデル:アソシエーションエンドの部品」は、アソシエーション・エンドに関連付けられている10個の要素のうち、基本部品「ロール名(rolename)」「誘導可能性(isNavigable)」「可視性(visibility)」までを解説しました。今回は基本部品の残りである「ターゲット・スコープ(目標範囲、targetScope)」に加え、JavaとUMLマッピングで重要となるアソシエーションの付加情報として「集約(aggregation)」「多重度(multiplicity)」「順序付け(ordering)」までを解説します。
ターゲット・スコープは、アソシエーション・エンドが有効となる範囲を表し、「オブジェクト」と「分類子」の2つで構成されます。「ターゲット・スコープがオブジェクトである」というのは、アソシエーションがオブジェクトの範囲で有効であるということです。通常のアソシエーションは、ターゲット・スコープがオブジェクトとなります。そして、「ターゲット・スコープが分類子である」とは、分類子のすべてのインスタンス・オブジェクトが同一のアソシエーションを持つことになる、ということを意味します。
●2.4.1 UMLでの表現
筆者はUML 1.4の仕様書からターゲット・スコープのノーテーションを発見できなかったのですが、属性での表現方法から類推して、「ターゲット・スコープが分類子の場合、ロール名に下線を引く」というように表現すると考えられます。本連載ではこの表記法を前提に議論を進めていきます。
図1は2つのターゲット・スコープを使用したクラス図です。クラスCompanyからクラスPersonの間には2つのアソシエーションが存在しています。上側のアソシエーションは、クラスCompanyからクラスPersonを参照するアソシエーションであり、クラスPersonがロールemployeeという役割で参加しています。このロール名はターゲット・スコープがインスタンスです。それに対して、下側のアソシエーションは、クラスPersonからクラスCompanyを参照するアソシエーションであり、クラスCompanyがロールemployerという役割で参加しています。このロール名には下線が引いてありますが、これが「スコープが分類子」であることを示しています。
●2.4.2 Javaでの実現
ターゲット・スコープもJavaとの対応関係が分かりやすいUML部品です。ターゲット・スコープが「インスタンス」の場合は、Javaの「インスタンス変数」に、ターゲット・スコープが「分類子」の場合は、Javaの「クラス変数」に対応します。
public class Company { private static Person employee; }
本連載のターゲットは、Javaによる実装を前提とした設計モデルにおけるUMLとJavaのマッピングです。このため、この設計モデルではJavaにそのまま変換できる精度のクラス図を描く必要があります。つまり、アソシエーション・エンドに関するさまざまな指定も正確に行う必要があります。
ここまで、アソシエーション・エンドの部品としてロール名、誘導可能性、可視性、ターゲット・スコープについて見てきました。Javaへのマッピングを前提とすると、以上の4つをアソシエーション・エンドの基本部品と考えることができます。そして、アソシエーションでは、必ず1つのアソシエーション・エンドにこれらの基本部品が設定されている必要があります。
アソシエーションは大きく分けて以下の3つに分類することができます。
これらのモデル要素は図2に示すような包含関係となっています。
つまり、アソシエーションには集約と集約でないアソシエーションの2種類のアソシエーションがあります。また、集約には合成集約と合成集約でない集約の2種類の集約があります。
●2.6.1 UMLでの表現
アソシエーション、集約、合成集約の違いは図3に示すように集約指示子によって指定されます。
集約指示子は所有者オブジェクト側のアソシエーション・エンドに表示されます。集約指示子がないアソシエーションは通常のアソシエーションです。白抜きのひし形が通常の集約を示す記号、黒いひし形が合成集約を示す記号です。
●2.6.2 Javaでの実装
Javaでのポイントとなるのは通常のアソシエーションと集約、合成集約の違いを直接Javaの部品で表現することができない点です。図2のアソシエーション、集約、合成集約はいずれも以下のJavaプログラムにマップされます。
public class Company { private employee Person; }
あえて違いを実装する場合は、以下のロジックをプログラム内で手作りで実装することになります。
もちろん、アソシエーション、集約、合成集約の違いはモデルの構成上本質的に重要なので、Javaとのマッピングとは関係なくUMLでの表現においては正確に記述する必要があります。
多重度は、1つのアソシエーションが、いくつのリンクとしてインスタンスされるかを指定します。
●2.7.1 UMLでの表現
図4に示すように、アソシエーション・エンド付近に多重度を示す文字として表示します。
値 | 意味 | 例 |
---|---|---|
数字 | 多重度が数字の値で固定 | 1 |
数字..数字 | 多重度が数字の範囲で可変 | 0..10 |
数字..* | 数字以上の多重度 | 0..* |
* | 0以上の多重度 | * |
表1 多重度の詳細 |
多重度におけるクラス図とオブジェクト図の関係は図5に示すようになります。クラス図上ではクラスCompanyとクラスPersonの間に1本のパスが張られているだけです。それに対して、オブジェクト図ではクラスCompanyのインスタンスであるオブジェクトXYZ商事から、クラスPersonのインスタンスであるオブジェクト鈴木さん、佐藤さん、山田さんにリンクが張られています。つまり、クラス図上は1本のアソシエーションだったものが、オブジェクト図上は3本のリンクとして実体化されているわけです。
●2.7.2 Javaでの実現
多重度をJavaで実現するためには、1つのインスタンス変数で複数のオブジェクトを一度に参照できる必要があります。この目的を達成するためのJavaの実現方法は以下の2つです。
さらに、コレクションにはたくさんの種類があり、どのコレクションを選ぶのかという問題も出てきます。つまり、多重度の実装に関しては、さまざまな選択肢があるため、UMLのクラス図から一意のJavaクラスにマップできるわけではないのです。このため何らかのプロファイルが必要となってきます。図5のクラス図におけるクラスCompanyを配列で実装すると以下のようになります。
リスト:配列
public class Company { private Person[] employee = new Person[10]; }
このプログラムでは、インスタンス変数としてクラスPerson用の配列を定義しています。またデフォルト値として大きさ10の配列オブジェクトを設定しています。配列を利用する場合、配列オブジェクトの大きさが固定であるという制約が考慮の対象となります。多重度が固定の場合、この例のようにインスタンス変数のデフォルト値として配列オブジェクトを設定しても問題ありません。しかし、多重度が可変の場合には、配列オブジェクトの生成のタイミングや管理には工夫が必要になってきます。
クラスCompanyをコレクションで実装すると以下のようになります。インスタンス変数の型としてjava.util.Collectionを指定しています。java.util.CollectionはJavaの標準コレクション機能におけるコレクションを示すインターフェイスです。デフォルト値としてjava.util.ArrayListを設定しています。java.util.ArrayListは、配列の機能の上に≪java.util.Listをimplementsした具象クラスです。java.util.Collectionの実装として最も普通に利用される具象クラスとなっています。
リスト:コレクション
import java.util.Collection; import java.util.ArrayList; public class Company { private Collection employee = new ArrayList(); }
コレクションを使う場合には、以下の点に選択肢が発生します。
インスタンス変数の型としては、まずインターフェイスにするのか実装クラスにするのかという選択肢があります。インターフェイスにした方が筋はよいですが、実装クラスのフルスペックを使いたい場合には実装クラスを型にする必要があります。インターフェイスの場合、以下のインターフェイスが基本的な選択肢となります。
java.util.Collection | オブジェクトの集まりを示すインターフェイス |
---|---|
java.util.List | 格納順序を持ったオブジェクトの集まりを示すインターフェイス |
java.util.Set | 集合、つまり重複のないオブジェクトの集まりを示すインターフェイス |
java.util.SortedSet | 重複がなくかつオブジェクトの値によって整列されているオブジェクトの集まりを示すインターフェイス |
以上のどのインターフェイスを型として選択するのかは、多重度以外の部品の組み合わせによって決まってきます。実装クラスは、型として選択したインターフェイスに対応したものを利用します。標準的には、図6に示す組み合わせが利用されますが、もちろん目的に応じて適切な実装クラスを選択していくことになります。
インターフェイス | 実装クラス |
---|---|
java.util.Collection | java.util.ArrayList |
java.util.List | java.util.ArrayList |
java.util.Set | java.util.HashSet |
java.util.SortedSet | java.util.TreeSet |
表2 標準的な選択 |
順序付け(ordering)は、多重度が2以上を持つアソシエーションにおいて、アソシエーション・エンドに関連付けられるオブジェクトに順序があることを示します。
●2.8.1 UMLでの表現
順序付けを使ったクラス図は図6となります。順序付けはアソシエーション・エンドに記述された制約orderedによって表現されます。多重度が2以上でないと意味を持たないので、図では多重度が「*」としています。
値 | 意味 |
---|---|
unordered | 順序付けなし |
ordered | 順序付けあり |
sorted | 整列あり |
表3 順序付けの詳細 |
制約unordered(順序付けなし)の場合には省略可能になっています。つまり、制約orderedや制約sortedが定義されていないアソシエーション・ロールは自動的に“順序付けなし”となるわけです。
●2.8.2 Javaでの実現
順序付きのアソシエーションは、Javaではjava.util.Listに対応します。図6のJavaでの実装は以下のようになります。
リスト:リスト
import java.util.List; import java.util.ArrayList; public class Company { private List employee = new ArrayList(); }
実装クラスとしてはjava.util.ArrayListを用いています。ただし、標準のコレクションライブラリの範囲でも、以下のクラスが選択肢となります。
以上のクラスの中から、目的に応じて適切なクラスを選択していくことになります。ただし、UMLの文法ではこれらの選択を適切に表現することができないため、何らかの工夫が必要になってきます。
以上、アソシエーションエンドの基本部品の残りである「ターゲット・スコープ(目標範囲、targetScope)」とアソシエーションの付加情報である「集約(aggregation)」「多重度(multiplicity)」「順序付け(ordering)」までを説明しました。第12回では、残りの付加情報「変更可能性(changeability) 」「限定子(qualifier) 」「インターフェイス指定子(interface specification)」まで解説し、アソシエーションにおけるUMLの部品の解説をまとめます。
Copyright © ITmedia, Inc. All Rights Reserved.