読者です 読者をやめる 読者になる 読者になる

オブジェクト間の関係

計算機 ノート Java

UMLについて調べています。思考の整理ツールとしての表記法(diagramming)には興味があります。

UMLは書きにくいし、曖昧さも強いし、目的が良くわからない絵が多いので、あまり好きにはなれないです。規格としては不完全なように思うので、独自に改変したり拡張したり制限しないと業務には使いにくそうです(Microsoft Officeで書けないし)。ちゃんと使ったことないし、世間を知らないので分からないけれども、世の中ではこれがそのまま使われているでしょうか?効率が悪そう……

さて、UMLではクラス図が最も基本的な図です。クラス図はクラスの関係を記述します。クラス図って、IDEで見れるアウトライン以上の情報を含んでいないので、こんなものは無意味だと昔は思っていました。しかしながら、クラス図に矢印で示されるオブジェクトの関係は、曖昧さを含むけれども、コードに明に現れなくて、かつ重要な概念を含んでいると思ったのでまとめようかと思います。*1

クラスの関係には以下の5種があります。

  • uses-a
  • is-a
  • has-a
  • owns-a
  • is-composed-of-a

名前は私が付けました。is-a関係とそれ以下の順序は微妙ですが、イメージとしては上から下にいくほどオブジェクト間の関係が強くなります。それぞれについて記します。

uses-a 関係 (Dependency)

f:id:fjkz:20160326204547p:plain

AクラスがBクラスに依存しているという関係 (Dependency)です。AクラスのコードにBクラスが現れているとき、AクラスはBクラスに依存していることになります。Javaで他のパッケージであれば、importと記述しなければならないクラスです。コンパイル時・実行時にCLASSPATHが通っていなければなりません。

継承している場合やフィールド値に持っている場合は以下のもっと強い関係となるので、ここには含みません。オブジェクトへの参照がスタック上にのみある場合がこの関係になります。

UMLでは点線の矢印で表します。依存している方からされている方に矢印が向きます。例の図は、Dogクラスがgrowlメソッドの返り値としてGrowlクラスを返す場合を想定しています。

A dog uses a growl.

なので(言葉としては違いますが)、uses-aとつけています。当然、growlメソッドを呼ぶオブジェクトが返り値を使用する場合はそのオブジェクトもGrowlクラスに依存することになります。

この関係を全て図にしたら収拾つかなくなりそうだし、依存関係を図示したところで何がうれしいのかは不明です。

is-a 関係 (Generalization)

f:id:fjkz:20160326211134p:plain

継承の関係です。特に言うまでもないです。Javaだと代入できる関係、もしくはinstanceoftrueになる関係です。

UMLだと矢印の先が白抜きになります。<<interface>>とわざわざ書いているし、区別する意義が不明なのだけれども、実装の場合は点線を使います。

has-a 関係 (Association)

has-a, owns-a, is-composed-of-aは全て基本的にはhas-a関係です。コードを見ても明には現れません。異なる実装になるかもしれないし、結果として同じ実装になることもあるかと思います。いずれの関係かは設計するときの気持ちで決まります。*2

f:id:fjkz:20160326215759p:plain

has-aというはフィールド値にオブジェクトの参照ポインタを持っているという意味です。

参照ですので、同じオブジェクトを複数のオブジェクトがhasしていても構いません。したがって、所有しているのとは意味が異なります。AクラスからBクラスを覚えている、AクラスからBクラスをたどることができるといった意味なので、knows-aとかcan-seeとかcan-touchとかの方が意味的には適当な気がします。

UMLだと開いた矢印で表します。逆向きに辿れないことを明に示すために矢印の根本に×をつけることもある。両方辿れる場合は矢尻がないこともあります。

例だとDogクラスは帰る家としてHouseクラスを持っています。矢印の上に"go back ▶"とか文脈を入れたりすると親切です。Houseオブジェクトは別のHouseオブジェクトに変わるかもしれないし、Houseオブジェクトは別のDogと共有されるかもしれないし、別のクラス(例えばOwner)と関連しているかもしれません。

owns-a 関係 (Aggregation)

f:id:fjkz:20160326233256p:plain

has-aより強い関連として、Aggregation (集約) という関係がある。集約の意味するところは不明です。オブジェクトが別のオブジェクトを所有しているという関係です。

オブジェクトを階層構造に並べた時に、Aggregation関係にあるオブジェクトは配下にあって、ただ関連してるだけのオブジェクトは横にならんでいて参照を持っているだけというイメージになるでしょうか?

UMLでは矢印の根本を◇にします。

例はちょっとイマイチというか、文脈の中でしか意味をなさないので、適当かどうかこれだけでは分からない。DogがCollarを所有しているという意味です。

is-composed-of-a 関係 (Composition)

f:id:fjkz:20160327000241p:plain

さらに強い関連として、Composition関係があります。全体と部分の関係です。切り分けていくと現れるということです。

part-ofのが自然ですが、向きが逆になってしまうので、is-composed-of-aとしています。

部分は常に1つのオブジェクトをComposeしています。つまり、2つ以上のオブジェクトが同じオブジェクトをComposition関係で配下に共有していることはありません。

全体と部分のオブジェクトは寿命はほとんど同じです。したがって、全体のクラスの、コンストラクタか初期化ルーチンで部分を生成して、途中で付け替えたりとかはしません。

Aggregation (集約) との区別は微妙です。設計者の気持ち的に、別に一個のクラスでもいいけど分けたよという意図が感じられればいいのかと思う。それぐらい関連が強いということです。

クラスが巨大になりすぎるから小さいクラスの集合に分けるときとかに使うのだと思う。しかし、あまりやり過ぎるとfan-out、つまり依存元の数が少なく依存先の数が多い設計となってしまい、これは凝集度が低い良くない設計と言われています。

UMLでは矢印の根本を◆にします。

参考

入門 UML 2.0

入門 UML 2.0

*1:私の理解を書いているので、UMLの説明としては正しくないと思います。UML自体の詳細は例えば参考に挙げた文献を当たってください。

*2:個人的にはこれらを区別できないことがオブジェクト指向という手法の問題だと思っているのですが、それについてはまだ考えがまとまっていません。