連載
Javaオブジェクトモデリング
第5回
静的モデル:データ型におけるUMLとJavaのマッピング(1)
浅海智晴
2002/10/1
クラス図の中核となるモデル要素は分類子ですが、この分類子の一種にデータ型があります。 データ型とJavaの関係は一見簡単そうに見えますが、まじめに考え出すとなかなか奥の深いテーマです。今回は、オブジェクト指向におけるデータの扱いを視野に入れたうえで、UMLのデータ型とJavaのマッピングについて説明します。
1.オブジェクトとデータ |
オブジェクトとはデータと手続きが統合されたモデル要素です。このオブジェクトを中核要素としてモデルを構築していくのがオブジェクト指向という考え方です。つまり、オブジェクト指向の技術体系の中で、データは“従”の立場になっているわけです。しかし、データそのものの価値がなくなってしまったのかというと、もちろんそんなことはありません。 オブジェクトに対して、データには以下のようなメリットがあります。
- データとして表現した方が、高性能が見込める
- データベースとの相性が良い
- 分散環境との相性が良い
つまり、オブジェクト指向においても、データをどのように扱っていくのかという点は依然として重要なテーマです。
■■1.1 オブジェクトとデータの違い■■
オブジェクトとデータとの違いで、最初に思い付くのは“振る舞い”の有無です。オブジェクトは振る舞いを持つことができるのに対して、データは振る舞いを持つことができません。
図1 UMLによるオブジェクトモデルとJavaオブジェクトの関係 |
第1回「連載を読む前に知っておくべきこと」で、UMLによるオブジェクトモデルとJavaオブジェクトの関係を説明しました。Javaオブジェクトの場合、静的な構造はインスタンス変数として実現されます。また、動的な挙動はメソッドとして実現されます。しかし、図1のオブジェクトでは「静的構造」と「動的挙動」以外に「Javaクラス」となっている場所があります。この「Javaクラス」として表現されているところは、オブジェクトとしての本質的な部位です。つまり、この部分がオブジェクトのIDということになるのです。ここで「UML仕様書」による定義を確認してみましょう。「データ型」とデータ型のインスタンスである「データバリュー」の定義は以下のようになっています。
DataType(データ型) | データ型は、その値が識別子を持たない型(純粋な値そのもの)とする。データ型はプリミティブな組み込み型(整数、文字列など)と、定義可能な列挙型(リテラルが真偽である論理型などの定義済みの列挙型)を含む。メタモデルでは、DataTypeは、Operationがすべて純粋な関数である特殊な型を定義する(OperationはDataValueを返すが、識別子を持たないので、DataValueを変えることはできない)。例えば、ある数に対する、ほかの数を引数とするadd操作は、結果として第3の数をもたらすが、結果と引数との数は変化しない |
DataValue(データ値) | データ値は、識別性を持たないインスタンスである。メタモデルでは、DataValueはInstanceの下位クラスで、状態を変えられない。すなわち、このDataValueに適用可能なすべての操作は、純粋な関数か問い合わせだけである。DataValueは典型的には、属性値として使われる |
以上のように、データ型は識別子すなわちIDを持たないという点が、定義の核となっています。 オブジェクト指向ではIDという概念が重要です。ここから派生して参照という概念も出てきます。JavaではオブジェクトのIDは言語仕様上、直接見えていませんが、暗黙のIDがあると考えることができます。つまり、IDを核にしたモデル要素であるオブジェクトを基本にモデルを構築するオブジェクト指向の中で、IDを持たないモデル要素であるデータをどのような形で用いていくのかという点がポイントとなるわけです。
2.UMLにおけるデータの位置付け |
それではUMLにおけるデータについて整理していきましょう。
■■2.1 分類子とデータ型■■
UMLはクラス的なものを分類子としてモデル化しています。図2は、第3回「静的モデル:クラスにおけるUMLとJavaのマッピング」で取り上げた分類子のメタモデル(本連載用に加工しています)です。図2からも分かるとおり、データ型はこの分類子の一種となっています。つまりUMLの表記上はデータもオブジェクトと同じような扱われ方をするわけです。
図2 分類子の種類(クリックすると拡大します) |
UMLのメタモデルではデータ型パッケージを定義しており、さまざまなデータ型が定義されています。ここで定義されているのが基本定義済み型です。この基本定義済み型はUMLのメタモデルを記述するために必要なデータ型なので、ユーザーがJavaプログラムの設計のために作成するUMLの図で利用する目的には、あまり便利なものではありません。StringやIntegerなど汎用的に利用できそうなデータ型もありますが、汎用の目的にはかなり不足しています。また結局のところ、Javaとのマッピングを考えなければならないので、利用しても便利になるわけでもありません。以上の点から、中途半端にUMLの定義したデータ型を用いるよりも、全面的にユーザー定義のデータ型を採用した方がよいでしょう。もちろん、Javaのためのデータ型ですから、Javaの言語仕様によるデータ型を採用することになります。
■■2.2 合成集約と属性■■
分類子がほかの分類子を完全に包含しているという関係を表現する方法には「合成集約(composition)」と「属性(attribute)」の2つがあります。合成集約と属性のUMLでの表現は図3となります。
図3 合成集約と属性 |
(1)は、分類子Sourceから分類子Targetに対する合成集約として、SourceとTargetのリレーションシップが定義されています。それに対して、(2)は分類子Sourceの属性として分類子Targetが定義されています。「UML仕様書」による合成集約と属性の定義は以下のものです。
合成集約(composition) | 全体の一部として強い所有関係があり、生存時間が同じである集約関係の1つの形態。多重度が決定されていない部品は、合成(クラス) 自体よりも後に生成されるが、いったん生成された後は、合成(クラス)と一緒に、生存し破棄される(つまり、生存時間を共有している)。このような部品は、合成(クラス)が破棄される前に、明示的に削除もできる。合成(クラス)は、再帰的である |
属性(attribute) | 分類子のインスタンスが持っている値の範囲を表現する分類子内の特性 |
つまり、合成集約はあくまでもクラス間の関係ですが、属性は分類子が持つ値であるということです。簡単にいうと、「値として取り扱う場合には属性を、オブジェクトとして取り扱う場合には合成集約を用いる」というのが1つの指針となります。以上のように、UMLの仕様上、属性と合成集約は厳密には異なるわけですが、実用上の観点では、条件を満たした合成集約は属性として表現するという選択もあります。
3.Javaにおけるデータの位置付け |
それでは、次はJavaにおけるデータについて整理します。
■■3.1 プリミティブ型と参照型■■
図4は、第3回「静的モデル:クラスにおけるUMLとJavaのマッピング(1)」にJavaの変数のモデルを説明したときの図です。図4からも分かるとおり、Javaの変数は値を格納する変数とオブジェクトへの参照を格納する変数の2つに分類できます。配列は少し特殊ですが、本質的にはオブジェクトへの参照を格納する変数ということになります。
図4 Javaの変数モデル |
プリミティブ型の変数は値を格納します。それに対して、オブジェクトを格納する変数は、オブジェクトに対する参照を格納しています。表1[Javaプリミティブ型の値域/精度]はJavaプリミティブ型の一覧です。値域と精度も併記しました。値としてデータを表現することができるプリミティブ型はUMLのデータ型の定義と完全にマッチしています。
表1 Javaプリミティブ型の値域/精度 | |
型 | 値域 |
boolean | true、false |
byte | -128以上/127以下 |
short | -32768以上/32767以下 |
int | -2147483648以上/2147483647以下 |
long | -9223372036854775808以上/9223372036854775807以下 |
float | IEEE単精度32bit浮動小数点数 |
double | IEEE倍精度64bit浮動小数点数 |
■■3.2 事実上のデータ型■■
Javaでは、UMLの分類子に相当するモデル要素としてプリミティブ型とクラスの2つのモデル要素を持っています。前述したように、プリミティブ型の定義はUMLのデータ型の定義と完全にマッチしています。また、Javaのクラスの定義も当然ながらUMLのクラスの定義と完全にマッチしています。以上の点から、Javaのプリミティブ型をUMLのデータ型、JavaのクラスをUMLのクラスにマップしてしまえば話は簡単です。しかし、実際にはこの方法には大きな問題があります。その問題は、あるオブジェクトが名前を持っているケースで、その名前をどのように表現するのかという、ごく普通のシチュエーションを考えると分かります。Javaでは、文字列の表現はjava.lang.Stringというオブジェクトを用います。ただし、java.lang.StringはJava言語の文法でも特別扱いされている事実上のプリミティブ型のデータであるという見方も成り立ちます。以上の点から、文字列によって名前を実装しているJavaクラスをクラス図で描くには、図5に示す2つの方法が考えられます。
図5 Stringの表現 |
(1)は合成集約を用いた表現方法です。java.lang.Stringはオブジェクトですから、UMLでの定義を厳格に適用するのであれば、この方法が有力です。(2)は属性を用いた表現方法です。(1)に比べてかなりすっきりした表現になりました。しかし、UMLにおいて属性を利用するためには、(オブジェクトではなく)値であることが必要です。このため、UML仕様とのミスマッチが問題となります。 UMLとJavaの関係をしゃくし定規に当てはめていくと、UMLのプリミティブ型をJavaのプリミティブ型に、UMLのクラスをJavaのクラスにマッピングしていくことになります。
しかし、このマッピング方法では、Stringのようなクラスでもクラスアイコンを用いた大げさな表現をしなければならなくなります。クラス図を描く目的の1つは、複雑なモデルの情報をコンパクトに表現することにあります。このため同じ情報量ならコンパクトな表現の方が望ましいといえます。つまり、この例では(2)の方法、つまり属性を用いる表現の方が目的にかなっているわけです。この問題は、「値を表現するためのオブジェクト」が存在すると考えると、うまく扱うことができます。本来のデータ型(Javaではプリミティブ型)に加えて、「値を実現するためのオブジェクト」もデータ型として考えるとよいわけです。ここでは、プリミティブ型のデータ型に加えて、「値を実現するためのオブジェクト」も事実上のデータ型として考えることにします。そして、この2つのデータ型を総称して“データ型”と呼ぶことにします。
■■3.3 Javaのデータ型■■
前述のようにプリミティブ型に加えて「値を実現するためのオブジェクト」も事実上のデータ型として考えることにしました。そして、これらのモデル要素を総称して“データ型”と呼ぶことにしました。 この観点から、代表的なJavaでの“データ型”をまとめたものが表2です。
表2 Javaのデータ型 | ||
プリミティブ型 | オブジェクト | 意味 |
boolean | java.lang.Boolean | ブール値 |
byte | java.lang.Byte | 8bit整数 |
short | java.lang.Short | 16bit整数 |
int | java.lang.Integer | 32bit整数 |
long | java.lang.Long | 64bit整数 |
float | java.lang.Float | IEEE単精度16bit浮動小数点数 |
double | java.lang.Double | IEEE倍精度32bit浮動小数点数 |
- | java.math.BigInteger | 無限精度整数 |
- | java.math.BigDecimal | 無限精度自然数 |
char | java.lang.Character | Unicodeコードポイント |
- | java.lang.String | 文字列 |
- | java.util.Locale | ロケール |
- | java.util.Date | 日時 |
- | java.util.Calender | 日時 |
- | java.net.URL | URL |
- | java.sql.Timestamp | 日時 |
- | java.sql.Date | 日付 |
- | java.sql.Time | 時間 |
Javaがサポートしているプリミティブ型はboolean、byte、short、int、long、float、double、charの8種類です。そして、これらのプリミティブ型にはそれぞれjava.lang.Boolean、java.lang.Byte、java.lang.Short、java.lang.Integer、java.lang.Long、java.lang.Float、java.lang.Double、java.langCharacterというオブジェクト版の実装が用意されています。java.lang.Stringは、文字列を表すオブジェクトです。Javaの言語仕様上、java.lang.Stringは特別扱いされており、事実上のデータ型となっていることは前述しました。java.math.BigIntegerやjava.math.BigDecimalは無限精度の整数や自然数のオブジェクトです。これらはプリミティブ型では実現しようがないので、オブジェクトの形式のものだけが用意されていると考えられます。 そのほか、さまざまなオブジェクトが“データ型”として用意されています。
1/2
|
Javaオブジェクトモデリング 第5回 | |
オブジェクトとデータ | |
バリューオブジェクトの導入 |
Javaオブジェクトモデリング INDEX |
IT Architect 連載記事一覧 |