💡

クラス図の情報量を激増させる線と多重度

2021/04/14に公開

「クラス図を書いてある人に説明資料として渡したいが、書いたことがないので何を書いておけば良いのかわからない」という話をした。

「これは大事じゃね」ってことをいくつか話したんだけど、それをさっとまとめて即席ポエムにしちゃおうと思ったのがこれ。

結論

個人的には 線の向き多重度 が超大事だと思っている。

線の向きは欲を言えば線の種類まで気をつけると良いと思う。

線の向きと多重度のあるなし

例えば、ある 箱と線だけ の適当な例を用意してみた。

ここから読み取れる 情報量 はどれくらいだろう?

登場する名詞くらいしかわからない。
これでコードは書けないな?

多重度 をちゃんと書いたらどうだろう?

多重度からわかること

線の端に書いてある*とか0..1のこと。

*は任意数を、n..mは最低 n 最高 m 個を、それぞれ示している。[1]

UserFavoriteをいくつでも登録できる、UserNickameを設定してもしなくても良い、ということが*0..1というちょっとのサインでわかってしまう。

線からわかること

向きのない絵ではUserPaymentの関係はわからない。
CreditCardPayPay両方の登録をPaymentとして取りまとめている絵とも読めてしまう。

だが 線の向き線の種類 があるだけで、UserPaymentを登録したい、かつUserからCreditCardPayPayかは認識できない様にしたい、というメッセージを受け取れる。

ただ線の終点を白抜き ( implement ) にするだけで、SOLID 原則の Dependency Inversion Principle をしたがっていることが一発で把握できてしまう。

構成 ( Composition ) と集約 ( Aggregation )

構成はオブジェクトのライフサイクルが連動するもの、親がないと子供も存在できない関係のこと。
黒塗りで示す。

集約は親がなくても子供だけで存在するもの、取りまとめる関係のこと。
白塗りで示す。

ただ僕はぶっちゃけこの違いにはあまりこだわりがない。

いつもは手抜きでどっちもただの--->で書いちゃってます。

ポイントは情報の密度

インスタンスのイメージ図はキリがないが、クラス図は定義的

この絵のクラスを実際にnewしてインスタンス ( 変数と思っても ok ) を想像しようと思うと、例えばこういう絵になる。

nicknameは 1 つでfavoriteが 3 つだから、正しい。

けど、これも

これも、正しい絵だ。

こういう絵を書いたらキリがないので、クラス図で*0..1を使って 定義的 に数をアピールしているんだ。

多重度ありクラス図は情報の密度がすごい高い気がするよね?

実装のイメージがブレない

この絵を Java 風味に実装すると、コードはこんな感じ。

class User {
    Option<Nickname> nickname
    List<Favorite> favorites
    Payment payment
}

0..1Optionに、*Listに、そのまま実装できる。
というかこれ以外実装しようがない。

ただ 多重度 を書くだけで、「コード書いたぜ」「えっニックネームって必須だっけ??」ということが限りなく起こらなくなる。

やっぱり多重度ありクラス図は情報の密度がすごい高い気がするよね?

別の絵でもう少し実感してみる

これはコンポジットパターンの絵だ。

少し不思議な感じがする絵だけど、多重度 からどんなパターンか読み取ってみる。

まず を見ると、DirectoryFileはともにEntryを実装している。これ自体はよく見る形だ。

次に 多重度 を見ると、DirectoryEntryを複数持てることがわかる。

つまりDirectoryEntry ( Directory | File )をいくつでも持ち、そのDirectoryがまたEntry ( Directory | File )をいくつでも持つことが示されている。

ファイラがたったこれだけで表現し終わっているんだ。

インスタンスのイメージ図だと、こんな感じ。

これだけの複雑な絵をたった 3 つの箱と 多重度 で示せてしまうなんて、すごい情報密度だと思わないか?

この絵じゃ無理だろう?

コンポジットパターンおまけ

あまり自分でこれを実装することはないけど、実は結構いろいろなところにいるぞ。

例えば HTML も似ている。

<div>みたいなタグを持てるタグと<br>みたいなタグを持たないタグを、この絵だけで表現できる。

List もこの絵で表現できる。

Javaslang というライブラリのListは、実際にこんな形をしている。

Consは値 1 つとList 1 つを持っていて、Nilは何も持たない。

ただこれだけでList("foo", "bar", "pon")が表現できる。

情報量すごいな?

まとめ

多重度 は書いておこう!!!

脚注
  1. 僕は1の場合は何も書かない。大半がそうだから。 ↩︎

Discussion