tag:crieit.net,2005:https://crieit.net/tags/%E3%82%AF%E3%83%A9%E3%82%B9%E5%9B%B3/feed
「クラス図」の記事 - Crieit
Crieitでタグ「クラス図」に投稿された最近の記事
2021-11-29T13:41:56+09:00
https://crieit.net/tags/%E3%82%AF%E3%83%A9%E3%82%B9%E5%9B%B3/feed
tag:crieit.net,2005:PublicArticle/16098
2020-10-04T23:17:50+09:00
2021-11-29T13:41:56+09:00
https://crieit.net/posts/UML-Python-Perl-PHP-UML-1
実践UML記述法:スクリプト言語(Python, Perl, PHPなどなど)における可視性をUMLで記述する1考察
<p>本記事は、 Qrunch からの移転記事です。</p>
<p>移転元: <a target="_blank" rel="nofollow noopener" href="https://morichan.qrunch.io/entries/Ry4qc9vnjI1JFXnB">実践UML記述法:スクリプト言語(Python, Perl, PHPなどなど)における可視性をUMLで記述する1考察 - 雑木林</a></p>
<h1 id="TL; DR"><a href="#TL%3B+DR">TL; DR</a></h1>
<p>スクリプト言語における可視性をUMLで記述する場合、リバースエンジニアリングによる結果論的可視性を書くといいかもしれない</p>
<h1 id="本題:スクリプト言語における可視性をUMLで記述する"><a href="#%E6%9C%AC%E9%A1%8C%EF%BC%9A%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E8%A8%80%E8%AA%9E%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E5%8F%AF%E8%A6%96%E6%80%A7%E3%82%92UML%E3%81%A7%E8%A8%98%E8%BF%B0%E3%81%99%E3%82%8B">本題:スクリプト言語における可視性をUMLで記述する</a></h1>
<p>UMLには可視性という概念があります。</p>
<p>Javaにおけるアクセス修飾子とほぼ同等のもの、と考えておけば間違いではありません。<br />
<code>public</code>、<code>private</code>、<code>protected</code>、および<code>package</code>です。</p>
<p>スクリプト言語(ここではPython、Perl、PHPといったいわゆるP言語を対象としておきます)には、絶対的な可視性はありません。<br />
例えばPythonであれば、変数の前にアンダースコアを付けることで「疑似的に」プライベート変数を設定できますが、実際に外部から参照できないわけではありません。</p>
<h2 id="問題点"><a href="#%E5%95%8F%E9%A1%8C%E7%82%B9">問題点</a></h2>
<p>スクリプト言語で開発する場合、UMLにおける可視性の情報は無意味です。<br />
それどころか、余計な情報として「ノイズ」と言われても仕方ありません。</p>
<p>UMLには可視性を書かなくても構文的に問題ないため、可視性の情報無しでも大丈夫です。<br />
しかし、それでは次のような問題が起こりえます。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKhEIImkLWWjJYrIgEPI08A2eioyaf3KYX8DJQvQBgYyPrvQVb5kOabcVXvKMGbG1PYHcrfSd9YU2b8BDaLNrqv1oJ0cBnEeHGbP8vT3QbuAq4e0" alt="UserクラスがInformationクラスと関連しているクラス図" /></p>
<p>UserクラスがInformationクラスと関連しているクラス図</p>
<pre><code class="plantuml">@startuml
class User {
printText()
}
class Information {
text
message
}
User --> "1\ninfo" Information
@enduml
</code></pre>
<p>さて、上記のクラス図から「UserクラスはInformationクラスのtext変数を参照しているが、message変数は参照していない」という情報を読み取れるでしょうか。</p>
<p>UserクラスがInformationクラスを持っているPythonコード</p>
<pre><code class="py">class User:
info = Information()
# クラス図におけるprintText()メソッドと対応
def print_text(self):
print ("{}".format(info.text))
class Information:
text = "This is printed"
message = "Oh no!"
</code></pre>
<p>お分かりの通り、クラス図からでは理解できません。<br />
しかし、クラス図から変数の利用状況が理解できなければ、結局コードを読まなければならず、UMLの浸透には貢献できません。</p>
<p>余談ですが、クラス図では<code>printText</code>とキャメルケースにしているところ、Pythonコードでは<code>print_text</code>とスネークケースにしています。<br />
これは、UMLがキャメルケース、Pythonがスネークケースを推奨しているためです。</p>
<h1 id="解決策"><a href="#%E8%A7%A3%E6%B1%BA%E7%AD%96">解決策</a></h1>
<p>発想を逆転します。<br />
設計時に可視性を決めるのではなく、コード上で利用しているか否かを判断し、それをUMLに反映してはどうでしょうか?</p>
<p><img src="http://www.plantuml.com/plantuml/png/JSun2i9G383XFQS8dHHve1UGEdPMDvTOemJxqfAa88ftzragc3NV7r9xaCMOE_2xw4166TkEt7SH9kSnk6bxtSkJSGqmRV3eRFW2B9DmCD4uy2CMItZ_HAFNtZA5z3h35KOnSvFPdMxyzTEjbBPORKwQK4fO_UTGirxAUny0" alt="UserクラスがInformationクラスと関連しておりmessage変数は利用していないクラス図" /></p>
<p>UserクラスがInformationクラスと関連しておりmessage変数は利用していないクラス図</p>
<pre><code class="plantuml">@startuml
class User {
- printText()
}
class Information {
+ text
- message
}
User --> "1\n- info" Information
@enduml
</code></pre>
<p>上記のクラス図から、「少なくとも」Informationクラスのmessage変数を外部クラスは参照していないことがわかります。<br />
また、他の変数(info)やメソッド(<code>printText()</code>)についても、外部からの参照はないことがわかります。</p>
<p>上記のクラス図を見ただけで、Informationクラスはtext変数にのみ注意すればよく、message変数はInformationクラス内部を見れば把握できることがわかります。</p>
<h1 id="結論"><a href="#%E7%B5%90%E8%AB%96">結論</a></h1>
<p>どうでしょう。<br />
あくまで視点を変えただけですから、「言われなくてもその通りじゃん」と言われればごもっともです。<br />
UMLを設計ツールとして可視性を考えるのではなく、UMLをあくまで可視化ツールとして利用するという考え方であれば、UMLを利用しやすくなるのではないでしょうか。</p>
Morichan
tag:crieit.net,2005:PublicArticle/16095
2020-10-04T23:14:35+09:00
2021-11-29T15:49:26+09:00
https://crieit.net/posts/UML
実践UML記述法:UMLのクラス図における関係の考察
<p>本記事は、 Qrunch からの移転記事です。</p>
<p>移転元: <a target="_blank" rel="nofollow noopener" href="https://morichan.qrunch.io/entries/3n3Rsvp6njvRJP7l">UMLのクラス図における関係の考察 - 雑木林</a></p>
<h1 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h1>
<p>UMLのクラス図には、ノードのようなもの(クラスやインタフェースなど)とエッジのようなもの(関連や依存など)を記述できます。</p>
<p>さて、クラスやインタフェースをプログラミング言語に落とし込むには、あまり苦も無く変換できると思います。<br />
私もクラス図とPerlの変換について、記事を書いたりしていました。</p>
<blockquote>
<p>クラス図とPerlの対応付け: <a target="_blank" rel="nofollow noopener" href="https://qiita.com/Morichan/items/cfa83fee6d451847ef85">https://qiita.com/Morichan/items/cfa83fee6d451847ef85</a></p>
</blockquote>
<p>しかし、エッジのようなもの(以降、関係と呼びます)は、汎化関係以外を書くのは難しいのが現状です。<br />
C++への変換において、「<a target="_blank" rel="nofollow noopener" href="https://www.researchgate.net/publication/220610417_Recovering_UML_class_models_from_C_A_detailed_explanation">Recovering UML class models from C++: A detailed explanation</a>」では、関係をC++に対応付けするためには意味解析 (semancit analysis) をする必要がある、と書かれています。</p>
<p>ここでいう意味解析という意味ですが、恐らくは構文解析だけでは瞬時に変換できず、構文解析結果を元にメモ化テーブルなどを作り、作成したメモ化テーブルから総合的に判断する必要がある、という意味だと私は捉えました。<br />
例えば、1つのクラス内に同じ名前のメンバ変数(Javaであればフィールドと呼びます)が複数存在する場合、コンパイルエラーとなりますよね。<br />
本来であれば避けるべきですが、構文解析だけでは判断できません。<br />
判断するためには、構文解析によってフィールドのリストをメモ化テーブルに入れておき、同じメンバ変数をメモ化テーブルから確認しなければなりません。<br />
他にも連想配列を使うとか、いろいろ方法はあると思いますが、どちらにせよ構文解析「だけ」では無理だということです。<br />
これを「意味解析をする必要がある」という意味で使っていると考えます。</p>
<p>さて、上記の論文において「意味解析をする必要がある」という意味が、私が捉えた意味だとするならば、構文解析を元に関係を変換できるのではないか、と考えることができます。<br />
以降は、私が考えたサイキョーの変換ですので、深く考えずに読んでいただければと思います。</p>
<h1 id="関係の種類と対応"><a href="#%E9%96%A2%E4%BF%82%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%A8%E5%AF%BE%E5%BF%9C">関係の種類と対応</a></h1>
<p>関係には、以下の6つがあります。</p>
<ul>
<li>実現</li>
<li>汎化</li>
<li>コンポジション</li>
<li>集約</li>
<li>関連</li>
<li>依存</li>
</ul>
<p>上部の関係が最も強く、下がるにつれて関係が弱くなります。</p>
<p>余談ですが、「関係」と言えば上記6つの関係を総称したものとして取り、「関連」と言えば関係の中の1種類のものとして取ります。<br />
よく勘違いしやすいので気を付けましょう。</p>
<p>以降、各関係をどう捉えるか、Javaを例にして考えてみます。</p>
<h2 id="実現"><a href="#%E5%AE%9F%E7%8F%BE">実現</a></h2>
<p>いわゆるインタフェースを実装しているクラスの関係です。<br />
クラス図では、下図のように記述します。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuShCAqajIajCJbLutBZrSLC_Z9p-k77-uwQcnuth5AgvQhcuadCIYuiLdgwR_s9nAufiPcv1JcfkQbv9CNuJ75BpKe0M0W00" alt="実現関係のクラス図" /></p>
<p>Javaにおいてはinterfaceとimplementの関係を書けばよいです。</p>
<pre><code class="java">interface ふわふわしたもの {
// ...
}
class 実装したもの implements ふわふわしたもの {
// ...
}
</code></pre>
<p>簡単ですね。</p>
<h2 id="汎化"><a href="#%E6%B1%8E%E5%8C%96">汎化</a></h2>
<p>いわゆる継承クラスの関係です。<br />
クラス図では、下図のように記述します。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKfCAYufIamkKNZMjVV5neNFPxKyRbprkAdfSUCwBamX1PiQNLs5fwtRqPL2X32LFcxgUDpKXKM3GsfU2j1-0000" alt="汎化関係のクラス図" /></p>
<p>クラス図では、抽象クラスとクラスの汎化関係、およびクラスとクラスの汎化関係の間に差異はありません。</p>
<p>Javaにおいてはextendsの関係を書けばよいです。</p>
<pre><code class="java">abstract class 抽象的なもの {
// ...
}
class 具象的なもの extends 抽象的なもの {
// ...
}
class より具象的なもの extends 具象的なもの {
// ...
}
</code></pre>
<p>こちらも簡単ですね。</p>
<p>つまり、実現と汎化については、構文解析レベルで判断可能です。<br />
ですから、これ以降について考えてみると面白いですよ。<br />
以降は答えがありませんので、各自考えてみてください。</p>
<h2 id="コンポジション"><a href="#%E3%82%B3%E3%83%B3%E3%83%9D%E3%82%B8%E3%82%B7%E3%83%A7%E3%83%B3">コンポジション</a></h2>
<p>is-part-of関係と呼ばれる関係です。<br />
クラス図では、下図のように記述します。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKhEIImkLb1wsRpYQKVRyrajZnjNFMvgUjouJaaXiLZ1EICp9uKBfkXfwuedUoTZA0f8B4hDA-7Y0YjMKD9LK7ZP35JOwwYaOAEhgmMJTqZDIm7Q2000" alt="コンポジション関係のクラス図" /></p>
<p>ここで、関連端名として「部位A」という文字と、その左端に可視性の「-」 (private) が登場しました。<br />
Javaで記述する際に利用するので、併せて覚えてください。</p>
<p>よく勘違いされる方がいますが、黒塗り菱形は持っている側に付きます。<br />
持たれる側に付くわけではありません、少しややこしいですよね。<br />
また、持たれる側の矢印はオプションです、あってもなくてもあまり意味はありません。</p>
<p>さて、Javaでどう書くかというと、私は「そのクラスだけがインスタンスを持っている」と捉えます。</p>
<pre><code class="java">class 部分的なもの {
// ...
}
class 全体的なもの {
private 部分的なもの 部位A = new 部分的なもの();
}
</code></pre>
<p>new演算子以降については、あっても無くても問題ありません。<br />
あるいは、コンストラクタ内に記述するというのも手でしょう。</p>
<pre><code class="java">class 部分的なもの {
// ...
}
class 全体的なもの {
private 部分的なもの 部位A;
全体的なもの() {
部位A = new 部分的なもの();
}
}
</code></pre>
<p>さて、これだけだと「ふーん、そんなものか」だと思われると思いますが、次の集約を見れば違いがはっきりすると思います。</p>
<h2 id="集約"><a href="#%E9%9B%86%E7%B4%84">集約</a></h2>
<p>own-a関係と呼ばれる関係です。<br />
クラス図では、下図のように記述します。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKhEIImkLb1wrjFuk77-uwQUnutB7ZUsF6xgVjpKzBXndP92Oh62SqPcJWeNYjB5sDG591QbvfLmSO7LAoZfAZphR02gVZgvqL59mKPNDn-cmY4rBmLeEG00" alt="集約関係のクラス図" /></p>
<p>さて、コンポジションとの違いは、黒塗り菱形を白抜き菱形に変更しただけです。<br />
この違いですが、is-part-of関係(つまり「全体的なもの」は「部分的なもの」の一部である関係)とown-a関係(つまり「持っているもの」は「持たれているもの」を所有している)という言葉の違いである、と考えました。</p>
<p>すなわち、Javaでどう書くかというと、私は「そのクラス以外にもインスタンスを(参照として)保持している」と捉えます。</p>
<pre><code class="java">class 持たれているもの {
// ...
}
class 持っているもの {
private 持たれているもの 所持品X;
持っているもの() {
所持品X = new 持たれているもの();
}
}
</code></pre>
<p>違い無しじゃないか!<br />
と思われたあなた、正解です。<br />
上記のクラス図では違いはありません。<br />
しかし、下図でははっきり違いが見えると思います。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuNhMq_YuSVxZffx7ZSiUDxOyRkf-tDJqk76TWfAkmhFE1g3qqycD4KeADhgw-GfWnOlHLE8n8YOFoP0eg27FroryFg7jSUDqDEN4EIKIQWfOgitmSUCIe0eyxbgCQHZK1K_NxtknSI74QrguNOLk4M4Z8maPwP2Qbm8CUm00" alt="複数の集約関係のクラス図" /></p>
<pre><code class="java">class 持たれているもの {
// ...
}
class 持っているもの {
private 持たれているもの 所持品X;
持っているもの(持たれているもの 所持品) {
所持品X = 所持品;
}
}
class もう1つの持っているもの {
private 持たれているもの 所持品Y;
もう1つの持っているもの(持たれているもの 所持品) {
所持品X = 所持品;
}
}
class 管理しているもの {
private 持っているもの 管理対象X;
private もう1つの持っているもの 管理対象Y;
private 持たれているもの 所持品Z = new 持たれているもの();
管理しているもの() {
管理対象X = new 持っているもの(所持品Z);
管理対象Y = new もう1つの持っているもの(所持品Z);
}
}
</code></pre>
<p>「管理しているもの」クラスのコンストラクタによって、「持っているもの」クラスのコンストラクタと「もう1つの持っているもの」クラスのコンストラクタに、所持品Zインスタンスを代入しています。<br />
Javaではインスタンスは基本的に参照渡しのため、「持っているもの」クラスの所持品Xと「もう1つの持っているもの」クラスの所持品Yと「管理しているもの」クラスの所持品Zは全て同じインスタンスを参照していることになります。</p>
<p>これが、私の考える集約です。</p>
<h2 id="関連"><a href="#%E9%96%A2%E9%80%A3">関連</a></h2>
<p>has-a関係と呼ばれる関係です。<br />
クラス図では、下図のように記述します。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuNenOU_ZneMF6vSzRcnvtDJzkAdfSUCw1ILTXUUTAv_idHoWf62Zgwlmj7yQN9BB8JKl1QWL0000" alt="関連関係のクラス図" /></p>
<p>実は、Javaにおいて一番ややこしい関係は、この関連だと考えます。<br />
すなわち、Javaでどう書くかというと、私は「実現、汎化、コンポジション、集約、依存のいずれにもあたらないが、依存より強い関係を持つ」と捉えます。</p>
<pre><code class="java">class 落ちているもの {
// ...
}
class 取るもの {
void hoge() {
落ちているもの 物体P = new 落ちているもの();
}
}
</code></pre>
<p>物体Pはhoge()メソッド内でのみ生存できます。<br />
つまり、「取るもの」クラスの属性にはあたりません。</p>
<p>基本的に、関連端名を書ける関係は、インライン属性として同じように記述できます。<br />
コンポジションのクラス図における「全体的なもの」クラスと同義のインライン属性を持つクラスの図を、下図に示します。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuIhEpimhI2nAp5L8paaiBdOiAIdAJ2ejIVLCpiyBpgnALJ3WKeT8AIYzR5xnjAFj-QoMnush7ZSrFMvSfwIGMApWd96PayB51LNqj7N5axsJCHG591QbvfKeL7Cf084k4Bzi1ghhTLImKi0qbgkMoo4rBmNeFW00" alt="コンポジションのクラス図における「全体的なもの」クラスと同義のインライン属性を持つクラス" /></p>
<p>これは逆に言えば、「全体的なもの」クラスの内部において、部位A属性をどの操作からでも参照できることを意味します。</p>
<p>しかし、関連における「取るもの」クラスの持つ物体P属性は、特定の操作内(メソッド内)でのみ生存するため、「取るもの」クラス内の別の操作が利用することはできません。<br />
そのため、関連における関連端名をインライン属性には変換できません。</p>
<p>UMLの仕様ではどうだったか定かではありませんが、確か全ての関係はインライン属性に変換可能だったような気がします [要検証] 。<br />
そのため、もしかしたらUMLの仕様とバッティングする恐れがあるので、この辺りは詳しく調査する必要がありそうです。</p>
<h2 id="依存"><a href="#%E4%BE%9D%E5%AD%98">依存</a></h2>
<p>とても範囲の広い関係です。<br />
クラス図では、下図のように記述します。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuIhEpimhI2nAp5L8paaiBdOiAIdAJ2ejIVLCpiyBpgnALJ3W0aieA3tPD_VfsXcF6wS-RkfvtBZiSMFBuwRknqrDZnlNAIaa5YiuPsJcf72XgvwEJMb0Ob5gNeb2DLSj5nTOcuADdXvKbCiXDIy5w380" alt="依存関係のクラス図" /></p>
<p>依存と聞くと、上記までの5つの関係全ても依存に書換えられる気がします。<br />
しかし、UML2.5.1の仕様では、依存 (Dependency) は直接関係 (DirectedRelationship) と汎化関係であり、関連 (Association) と汎化 (Extension) とは異なるものとして定義されています。<br />
実現 (InterfaceRealization) は依存と汎化関係であるため、実現については依存に書換えようと思えばできる関係と言えるでしょう。<br />
ちなみに、集約 (Aggregation) とコンポジション (Composition) は、属性 (Property) の種類を表す列挙子 (AggregationKind) として設定できるみたいで、こちらも全く異なります。</p>
<p><img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKfCAYufIamkKGXApKaioSpFAyx8B428kcGMfIQNfAQWo78XynHiQdHriQl3LEPON9oVd0aMv89hmJGijI0rBoKrBxcI2y646W1n6DW093P4qZEl9BKeBJ4vDIWrCIUp2c8Dr4g4AjUAajIyOf2K0z1eO1W00000" alt="UML2.5.1の仕様における関係の定義" /></p>
<p>UML2.5.1の仕様では確かに書換えられないようですが、実際問題として「依存」という名前だけではよくわかりません。<br />
ではUML2.5.1の仕様を読めば解決するのかというと、そうでもなさそうです。</p>
<blockquote>
<p>A Dependency is a Relationship that signifies that a single model Element or a set of model Elements requires other model Elements for their specification or implementation.</p>
<p>意訳: 依存は、とあるクラス(ここでは要素ではなくクラスと読んで差し支えない)の仕様や実装のために、別のクラスを必要としていることを意味する。</p>
</blockquote>
<p>つまり、実装に必要であればいいようです。</p>
<p>ということで、Javaでどう書くかというと、私は「依存先のクラスをどこかしらで利用しており、上記5つの関係以外の場合全てを表す」と捉えます。</p>
<pre><code class="java">class 依存されているもの {
// ...
}
class 依存しているもの {
// ...
void hoge(依存されているもの 引数S) {
// ...
}
}
</code></pre>
<p>例えば上記のように、メソッドの引数の型について、現状クラス図では定義することが難しいです。<br />
ですが、依存を書くことで、どこか関係性があるのだろうことは理解できます。</p>
<p>他にも、キャストのためだけに呼ばれているとか、調べればいろいろ利用法が出てきそうです。<br />
どちらにせよ、クラス図からJavaに変換する際には利用できそうにありません。<br />
Javaからクラス図に変換する際に利用する関係だと思います。</p>
<p>煩雑になりすぎてしまう問題は、容易に想像できます。<br />
しかし、UMLはいわゆるダイアグラムですから、読みづらければ非表示にすればよいだけです。<br />
全てを表示する必要はなく、ダイアグラムの利用目的のために表示内容を変えるのは手だと思います。</p>
<h1 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h1>
<p>私がUMLを研究していて、いつか挑戦してみたいことを書いてみました。<br />
もう修士課程は終盤直前ですが、もしこの話に興味があれば、勝手に使ってかまいません。<br />
もちろん、このサイトから引用したなんて野暮なことは書かず、自分で定義し、その理由付けも自分で行ってくださいね。<br />
その論文ができたら、ご一報くださると嬉しいです。</p>
<p>UMLに未来があることを願います。</p>
Morichan