【UMLモデリングありがちな間違え】種類を表現する

この連載では、UMLモデリング初心者が陥りやすいモデル化の例を紹介し、合わせて適切なモデリング例を解説します。

本来は、そのモデリングのコンテキストつまりモデリングする目的や対象システム・顧客のゴールなどの制約が与えられないと、そのモデリングが適切か不適切かは言い切れないのは事実です。しかし、モデリングを学び始めた入門者にとっては、基本の「型」として普通はこうするというパターンを頭に入れておくことは大事です。その意味で、基本の定石としてまずは頭に入れておいて欲しいことを、この連載では取りあげていきたいと思います。実践の場でそれらの定石が崩されることは、ときとして起こりますが、その場合もこういう理由で今回は定石を崩してモデリングしているという「意識」をもてることが大事だと思うからです。

ではさっそく始めて行きましょう。

:::note info
【問題】以下をモデル化してください。

＜会社の設立＞

会社には４つの種類があります。株式会社、合同会社、合資会社、合名会社の4つです。
::: 

#【よくある間違え（１）】種類をクラスの属性にする
![UML_MISS_01_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197297/6549a88d-e767-eb07-cdf5-42f5ab1056b3.jpeg)
これは、最もよく見る間違えです。

なぜ「会社種別」を「会社」クラスの属性にしてはいけないのでしょうか？
ただ単に、会社の種類だけに関心があるだけならば、このモデルでも何も困らないかも知れません。

しかし、たとえば株主の存在をモデルに加えたときどうなるでしょうか？
![UML_MISS_01_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197297/23c7deea-9729-e308-349e-1e7e97fdae92.jpeg)
株式会社に関しては、これでも問題は起きません。

しかし、そもそも、株式会社以外の会社には、株主は法的に存在しません。

そう言われたら「それならば、株式会社以外の時は、株主側の関連端の多重度が[0]だと考えれば良いのではないの？」と考えるかも知れませんね。
実際にソフトウェアの設計実装に進めてしまうことも（良いことではありませんが）可能です。

このようなモデルを元にして、ソフトウェアの設計実装に進んだ場合、どうなるでしょうか。
 

通常ならば「会社」クラスの中に

```cpp:qiita.cpp
// 会社の種類が株式会社の時以外は、株主を無視する

if( this.種類 != 会社種別.株式会社 ) {

    return;

}
```

のような処理が、複数混在しはじめ、不具合の温床になることでしょう。
多くの人が、悪いコードだと感じるパターンですね。
 

このように、会社の種類を「会社」クラスの属性にして表現してしまうと、「会社」クラスが全種類の会社の特徴を持つことになります。
結果、会社の種類を判断するif文を多く含んだクラスを作ってしまいます。

このモデルをベースに、ソフトウェア開発を進めれば、ほとんどの場合、不具合収束に時間のかかる開発プロジェクトになってしまうでしょう。

これほどまでに、モデリングは重要なのです。

上記の例では、会社種別を列挙体で宣言していますが、下記のようにノートで記載した場合も同じことです。

![UML_MISS_01_03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197297/b898a1a3-8616-ada0-47be-d098f407c3eb.jpeg)

#【よくある間違え（２）】「会社」クラスが抽象クラスになっていない

![UML_MISS_01_04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197297/4f33a136-0925-8f33-86df-e9492a59f731.jpeg)

なぜ、「会社」クラスを抽象クラスにしなければならないのでしょうか？

この問題の場合、モデリングする文脈は「会社の設立」です。
抽象クラスにしないならば、「会社」クラスは「インスタンス化できる」ことを意味します。

つまり、会社を設立しようとして、どの種類でもない漠然とした「会社」のインスタンス（下図では「U社」）を設立できてしまうことになります。

![UML_MISS_01_05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197297/48511cad-63b3-fc5b-cdf9-1cef3cf69f79.jpeg)

仮に、モデリングして法務局の会社登録システムを開発したならば、どの種類にも該当しない会社を登録できてしまうとすると、大変なことですね。そんなシステムを一度開発してしまったら、パッチを当てて不具合修正を続けたり、機能追加をしたりして、本当に大変な混乱を招いてしまいますね。

#【適切なモデリング例】
![UML_MISS_01_06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197297/e47f9314-9393-bfeb-f76d-4e7ef38e3dc6.jpeg)
「会社」クラスは抽象クラスにします。抽象クラスは、インスタンス化することができないクラスですから、「会社」クラスのインスタンスとしての会社（下図のU社）を作ることが出来なくなります。
![UML_MISS_01_07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197297/bad57652-f397-d224-6afc-15f75d0f0517.jpeg)
また、抽象クラスはクラス名が斜体表記になります。

このように会社の種類をそれぞれクラスにすると、種類ごとの会社の特徴を各クラスに定義することが出来ます。

たとえば下図では、「株式会社」クラスにのみ「株主」（との関係）という特徴を表現できています。
![UML_MISS_01_08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197297/ce9e0e2e-12b2-8a07-2187-34c2bb3eeea0.jpeg)
このようなモデリングをしているならば、設計・実装になっても、「合同会社」・「合資会社」・「合名会社」の各クラスには、関係のない「株主」を意識するコードが入り込むことはありません。不具合が混入しづらくなりますね。

モデリング、特に概念的なモデリングは、ソフトウェア開発の最終成果物（実装コード）とは直接的な関係のないスケッチに過ぎないと考えがちですが、それは大きな間違いです。適切な概念モデリングのおかげで、不具合混入が少なく不具合収束に時間のかからないソフトウェア開発が可能になるのです。
 

注）本連載では「間違い」ではなく敢えて「間違え」という言い方を採用しています。「間違い」という断定的な名詞ではなく、「間違え」という人間の活動の１つのスタイルという意味合いを強調したためです。

#関連記事
本記事は、豆蔵HPにも同文にて掲載されています。
関連記事は、こちらより辿れます　＞ [元の記事](https://www.mamezou.com/techinfo/modeling_ddd/uml_miss_01)