Skip to content.

Sections
Personal tools
You are here: Home » 技術文書 » UML » Java ソースと見るUML入門

Document Actions
Javaソースと見るUML入門
(株)永和システムマネジメント    梅田 政利
初出:技術評論社刊『JAVA PRESS vol.31』
 はじめに

本章では、UMLのダイアグラム(図)の基本的な描き方を取り上げます。 Java言語入門レベルを卒業した方が対象ということなので、 Java言語を題材にUMLを学んで行きましょう。 厳密なものではありませんが、ソースコード付きの例を示すことで、 この章を参考にしながら図を描けることを目的としています。 ソースコードと言いましても、文法的に難しいものは出しませんので、 Java言語に対する知識がない方でも、オブジェクト指向言語に対する知識をお持ちであれば 問題なく理解できると思います。一般に取り上げられる順序とは多少異なるかもしれませんが、 今回は以下の順で図を扱います。

それでは始めましょう。


クラス図

パッケージ構成も含めたソフトウェアの構造を表現する図です。 わかりやすく言うと、Javaのクラス(インターフェースも含みます)の仕様と クラス間の関係を表現するのに使用します。


クラス


最初に、中身がないSampleClassを作りましょう。

public class SampleClass {
}

このクラスにフィールドとメソッドを追加するとこうなります。

public class SampleClass {
  private int value;
  private String str;
  public void setValue(int value) {…}
  public int getValue() {…}
}

これで、とても基本的なクラスが描けるようになました。 この場合、クラスを表す長方形は3つの区域に分かれます。 上からクラス名の区域、フィールドの区域、メソッドの区域となります。 フィールドは、"可視性 名前:型 = 初期値"で表します。 メソッドは、"可視性 名前(引数リスト):返り値"で表し、 引数リストは、"名前:型"をコンマで区切って並べます。 可視性は記号で表すことができるので、表を参照してください。

表: 可視性
表記意味
+public(どこからでもアクセス可能)
#protected(クラス内および派生したクラスからアクセス可能)
-private(クラス内でのみアクセス可能)
~package(パッケージ内でアクセス可能)

次に、フィールドやメソッドをstaticにしてみましょう。 どちらも、次のように下線をつけて表現します。

public class SampleClass {
  private static int value = 0;
  public static void setValue(int value) {…}
  public static int getValue() {…}
}

さて、次に抽象クラスを表現しましょう。 抽象クラスの名前とメソッドが斜体で表現されます。

public abstract class SampleClass {
  private int value;
  public abstract void abstractMethod(int value);
}

例としての面白味はありませんが、 これで色々なクラスを表現することができるようになりましたね。


TIPS - ノート

staticなフィールドといえば、final宣言が付きものです。 UMLでは、finalの表現も規定されているのですが、 私は一度も図上で表現されているものを見たことがありません。 しかもキーワード的には、"frozen"となりますので、UMLを普段使用している人でも、 意味がわからない可能性もあります。 そこで利用するのが「ノート」です。 「ノート」は、全ての図において使用できる要素で、文章を貼り付けることができます。 これは、単独で置いたり、対象と破線によって結びつけたりできます。 そういうわけで、「ノート」に"final"と記述して、フィールドに結び付けましょう。 Javaを知っている人なら、誰でもわかりますよね。



  関連

クラス間の関係を実線で表現します。 ソースコードでは一般的にフィールドとして現れます。 しかし、この説明だけだとクラスのフィールド欄に記述するのと同じですよね。 では、どのように使い分けるのでしょうか? 指針となるのは、「クラス間の関係を図に表したいかどうか?」という点です。 関連で表現している場合は、クラス間の関係を見落とすことはまずありえないでしょう。 また、図が複雑になってくると図の理解が難しくなってきます。 そのような場合には、特にその図で注目する必要のない関連は、 クラスのフィールド区域で表現してしまいましょう。 図がシンプルになり、理解しやすい図ができあがります。

ここでマシンキャット(MachineCat)について考えてみましょう。 例として複雑になるのは避けたいので、特徴的なところについて考えます。 道具袋になるポケット(Pocket)と、ポケットから出し入れするアイテム(Item)、 そして電源スイッチになる尻尾(Tail)を持たせてみましょう。 関連の端のほうにある名前がフィールド名にあたります。 この名前の頭には可視性が付きます。 また、名前の近くに数字や'*'が記述されているものもありますね。 これは、対象となるクラスのインスタンスをいくつ参照するかを示しています。 '*'は0以上を意味し、'n'と記述する場合もあります。

public class MachineCat {
  private String dateOfManufacture;
  private Pocket pocket;
  private Tail tail;
}

public class Pocket {
  private Vector items;
  public void takeIn(Item item) {…}
  public Item takeOut(String name) {…}
}

public class Item {
  private String name;
}

public class Tail {
}


汎化


Javaの継承"extends"です。継承先から継承元へ伸びる三角矢印の実線で表現します。 マシンキャットを拡張しましょう。ロボットらしく、別スレッドで動くようにします。

public class MachineCat extends Thread {
  private String dateOfManufacture;
  private Pocket pocket;
  private Tail tail;
  public void run() {…}
}


実現


Javaの"implements"です。マシンキャットに電源ON/OFFのインターフェース(PowerControl)を付けましょう。尻尾を引くことで本体の電源ON/OFFが可能です。 implementsを表現する前に、まずはインターフェースを表現する必要がありますね。 UMLではクラスに<<interface>>とステレオタイプ(TIPSを参照)を付けることで、インターフェースを表現します。

public interface PowerControl {
  public void powerOn();
  public void powerOff();
}

implementsは、実装クラスからインターフェースへ伸びる三角矢印の点線で表現します。 また、TailクラスからPowerControlインターフェースへの関連だけ、先のほうが矢印に なっています。これは関連の方向性を表しており、矢印の反対方向への参照が存在しな いことを意味しています。インターフェースからの逆参照はありえないため、この点で のみ使ってみましたが、もちろんこの図の他の関連にも適用できます。

public class MachineCat extends Thread implements PowerControl {
  private String dateOfManufacture;
  private Pocket pocket;
  private Tail tail;
  public void run() {…}
  public void powerOn() {…}
  public void powerOff() {…}
}

public class Tail extends Thread {
  private PowerControl listener;  // 電源ON/OFFの通知対象(MachineCat)
}

また、ステレオタイプにはアイコン表記という表現方法があります。 インターフェースをアイコン表記に変えることも多いので、そちらの図も見ておきましょう。 アイコン表記にした場合には、implementsを表す三角矢印の点線が、 矢印を持たないただの実線になる点に注意が必要です。


TIPS - ステレオタイプ

ステレオタイプとは、UMLの拡張メカニズムと呼ばれるもので、 アプリケーションや問題領域固有の意味を、モデルに表現するために付加する文字列です。 いくつかのステレオタイプが規定されていますし、自分で規定することも可能ですが、 まずは<<interface>>だけを知っていれば問題ないでしょう。 しかし、今後のために、代表的なステレオタイプを紹介します。


表: ステレオタイプ
ステレオタイプ 意味 アイコン表記
boundary 外部とのインターフェース
control 処理の流れを管理する
entity 問題領域を表現するデータ


依存


相手が変更されたときに影響を受ける関係を表現します。メソッドの引数に使用するク ラスや、一時変数として使用するクラスに対する関係を表現します。マシンキャットは、 助け(requestHelpメソッド)を呼ばれると、(helpメソッドを内部で呼び出して)アイテム を取得して人助けします。このとき、マシンキャットは、アイテムに依存関係を持ちま す。依存は、マシンキャットからアイテムに伸びる点線矢印で表現します。

public class MachineCat extends Thread implements PowerControl {
    …
  public void requestHelp() {
    // イベントとしてキューに追加する.
  }

  private void help() {
    Item useItem = pocket.takeOut("…");
    // help someone.
  }
    …
}


パッケージ


クラス図ではパッケージを含んだソフトウェア構造も表現できます。 パッケージとパッ ケージ間の関係のみに注視した図を、 特にパッケージ図と呼ぶこともありますが、クラス図の一種です。 簡単なパッケージ図と、パッケージを含んだクラス図を見てみましょう。

(パッケージ図)

(パッケージを含んだクラス図)


 オブジェクト図

クラス図では、ソフトウェアの静的構造を表現しましたが、 オブジェクト図では、ソフ トウェアのある時点での情報を、オブジェクトの集まりで表現します。 オブジェクトとは、クラスが実体化したもので、インスタンスとも呼ばれます。 長方形の中に、 「オブジェクト名:クラス名」で記述し、名前の一部を省略して、 「オブジェクト名」や「:クラス名」と記述することも可能です。

それでは、help動作中のマシンキャットをオブジェクト図で表現しましょう。 マシンキャットがポケットと尻尾、それに、ポケットから取り出したアイテムを参照しています。 ポケットから取り出したため、ポケットはアイテムを参照していません。 オブジェクト の下の区域には、ある時点でのフィールドの値を表現できます。 また、オブジェクトは、後述のシーケンス図とコラボレーション図でも使用しますが、 一般的にフィールドの値 は表現しません。

 シーケンス図

メソッドの実装などを表現する図で、 オブジェクトの相互作用を時間軸に沿って表現します。 後述するコラボレーション図とともに、相互作用図の1つですが、 処理の順序をわかりやすく伝えたい場合には、 シーケンス図を用いることが多いでしょう。


  同期メッセージと返り値

通常のメソッド呼び出しは同期メッセージです。 同期メッセージは、塗りつぶした三角の矢印で表します。 また、返り値を伴うメッセージも表現でき、メッセージ名の最初に"変数 :="と記述できます。 点線矢印はリターンを表していますが、これは省略可能です。 MachineCatクラスのhelpメソッドにおいて、 同期メッセージによりポケットからアイテムを取り出すところを図にしてみましょう。


  非同期メッセージ

非同期メッセージとは、呼び出し側が処理の完了を待たされずに、 呼び出した処理が行われるメッセージです。 例えば、Threadクラスのstartメソッドを呼び出した場合、すぐに呼び出しから復帰し、 Threadは動き始めますよね。これが非同期メッセージです。 非同期メッセージは、矢印で表します。 マシンキャットのrequestHelpメソッドを呼び出した場合も、すぐに呼び出しから復帰し、 マシンキャットは人助けを行います。この動作を図にしましょう。

  if文

尻尾は1度引くとスイッチON、さらに引くとスイッチOFFというように、動作します。 尻尾を引かれるとchangeStateメソッドが呼び出されるわけですが、changeStateメソッド 呼び出しからマシンキャットに電源ON/OFFを通知するところを図にしてみましょう。

public class Tail extends Thread {
  private PowerControl listener;
  private static final int PowerOn = 0;
  private static final int PowerOff = 1;
  …
  public void changeState() {
    if (oldState == PowerOn) {
      listener.powerOff();
      oldState = PowerOff;
    } else {
      listener.powerOn();
      oldState = PowerOn;
    }
  }
  …
}

TIPS - オブジェクトの生存期間

シーケンス図において、オブジェクトの生存期間に注目させたいことがあります。その とき利用するのが、createとdestroy、そしてterminationです。コンストラクタを呼び 出す状態を表現するのがcreateです。nullを代入するなどして参照を外したり、スコー プから外れることで、ガベージコレクションによりメモリを解放可能になる状態を表現 するのが、それぞれdestroyとterminationです。

(createとdestory)

(createとtermination)

 コラボレーション図

オブジェクト間のメッセージのやりとりを、接続関係に着目して表現した相互作用図で す。レイアウトを工夫することで、シーケンス図よりもオブジェクト間の関係がつかみやすくなります。マシンキャットが助けを求められてから、道具を取り出すところを図 にしてみましょう。


 状態図

ひとつのオブジェクトの状態変化を表した図で、外部からの入力と、それに対するオブジェクトの状態遷移を表します。ひとつのオブジェクトと言っても粒度は様々で、分析レベルではシステム全体をひとつのオブジェクトと見なすこともあります。 オブジェクトがとる状態を状態(そのままですね)と呼び、角が丸くなった矩形で表します。状態名の下の区画には表に示した動作が記述できます。また、状態遷移は、"イベント名[条件]/処理"のように記述し、そのイベントが起きたときに条件を満たしていれば遷移を行い、そのとき指定された処理を実行します。記述としては、"イベント名"、"イベント/処理"のように、不要なものは省略することができます。自分自身へ遷移するイベントも記述でき、自己遷移と呼びます。

表: 状態に記述する動作
種類 動作記述
entry/ その状態に入ったときに実行する処理を記述します
do/ その状態で実行し続ける処理を記述します
exit/ その状態から出るときに実行する処理を記述します
イベント/ その状態内で処理するイベントと、そのイベントが起きたときに実行する処理を記述します

それでは、先ほどシーケンス図で表現した尻尾を引かれたときの Tailクラスの動作を状態図で表現しましょう。 Tailオブジェクトでは、尻尾を引かれるたびにPowerOnとPowerOffの間を遷移します。 イベントが起きたときに遷移を行う条件はありません。 PowerOnになる場合は、マシンキャットのpowerOnメソッドを呼び出し、 PowerOffになる場合は、powerOffメソッドを呼び出します。



ここからは、JavaMailを利用したソフトウェアMyMailerを作成していると仮定して、いくつかの図を紹介しましょう。最初に、MyMailerで提供される機能をユースケース図で表現します。次に、提供される機能の中からある機能を取り上げて、アクティビティ図 で処理の流れを表現します。さらに、ライブラリとの関係をコンポーネント図で表現し、 システム構成を配置図で表現します。これらを例に、それぞれの図がどのような用途で 使用されるかを見ていきましょう。

 ユースケース図

システムの機能(ユースケース)と、ユーザなどの外部環境(アクター)との関連を表 します。図を読み取るのに専門知識は必要なく、しかも一目でシステムの機能やシステ ム外部と内部の境界を理解することができます。そのため、ユーザやクライアントとの 意識統一を図ることが容易になります。というと、大層なものに思われるかもしれませんが、ユーザに提供したい機能に名前を付けて楕円で囲んだものと、機能を提供されるユーザを人型で表したものを、線で結ぶとできあがりです。ほとんどの場合はこれで十分です。この楕円をユースケース、人型をアクターといいます。 それでは、MyMailerを表現しましょう。一般ユーザに提供される機能は、「メールを送 信する」「メールを受信する」「メールを読む」「メールを消す」の4つです。一般ユー ザがアクターに、機能群がユースケースとなります。ユースケースを囲んでいる矩形が、 Mymailerを表すシステム境界線です。 ユースケース図を作成するときに、「どの粒度でユースケースを抽出すれば良いですか ?」と、よく質問されます。ユーザから見た機能の粒度で定義することが望ましいでし ょう。

これだけでは、図の表現力が足りませんので、いくつかのバリエーションを紹介しまし ょう。


  アクターの継承

MyMailerには、「一般ユーザ」の他に「登録ユーザ」がいます。「登録ユーザ」には、 受信したメールをフォルダに振り分けて管理する機能も提供されます。「登録ユーザ」 から、全てのユースケースに関連を引くと見難いですよね。アクターに対しても、クラ スと同様に継承を用いることができます。継承を用いると、全ての関連を引き継ぐこと になりますので、図がすっきりとまとまって、理解しやすくなります。

  <<include>>

複数人で使用するパソコンで利用した場合に、だれもがMyMailerを起動できてメールの 中身を見れるのは、セキュリティーに問題がありますよね。起動時に「ユーザ認証」を 行うように、MyMailerの仕様を少し拡張しましょう。この「ユーザ認証」は、メール受 信時にも行います(自動で行うように設定可能です)。このように、あるユースケース を他のユースケースに含むときには、<<include>>を使用します。includeは、依存の線に<<include>>というステレオタイプを付けた形で表現します。このとき、ユースケースに含むユースケースを矢印で指し示します。


  <<extend>>

登録してくれるユーザ数を増やしたいと考えました。MyMailerの終了処理後に、「登録 のお知らせ」を表示することにします。このように、あるユースケースをあるタイミン グで拡張したいときには、<<extend>>を使用します。extendは、依存の線に<<extend>>というステレオタイプを付けた形で表現します。このとき、拡張する機能を新たなユースケースとして、拡張されるユースケースを矢印で指し示します。拡張されるユースケースには、どのポイントで拡張が発生するかを「拡張点」として記述し、<<extend>>には、拡張条件を記述します。これらは省略可能です。

それでは、全ての要素をまとめてみましょう。最終的な図はこのようになりました。 MyMailerの機能がうまく表現されていますよね。


 アクティビティ図

業務や処理の流れを表すために、関連する複数の業務手順や処理ステップを順序だてて 配置したものです。ワークフローからユースケースの処理フロー、もちろん、メソッド のアルゴリズムなど、手順のあるものなら色々なことが表現できます。 図について見てみましょう。まずは、黒く塗りつぶした円からスタートします。アクシ ョン状態と呼ばれる楕円で処理内容を示し、処理が済むと矢印で導かれる次のアクショ ン状態に遷移します。また、処理の流れを選択することや連結することができます。選 択の場合には条件記述を"[]"で囲んで記述します。この「終了する」ユースケースを説 明するアクティビティ図では、ユーザ登録されていないユーザに対して、終了処理の後 に「登録のお知らせ」を行うことを表現しています。


  コンポーネント図

コンポーネント間の依存関係を表す図です。コンポーネントとして表現できるものには、ソフトウェアやjarファイル、ソースコードなどがあります。MyMailerでは、JavaMailのmail.jarを利用するため、mail.jarに対して依存の関係を持ちます。さらに、mail.jarは、JAFのactivation.jarを利用します。この場合のコンポーネント図は次のようになります。


 配置図

することができます。ノードとは、サーバやクライアント、プロセッサやデバイスを抽 象化したものです。配置図において、コンポーネントはインスタンスになる場合があり、 インスタンスになる場合は、名称に下線を引いて表現します。図に出てくるコンポーネ ントは全てメモリ上に作成されるものなのでインスタンスにしています。また、通信プ ロトコルなどを指定したい場合には、ノード間の関連にステレオタイプを付けることで 指定できます。この図では、TCP/IPによって通信していることを表現しています。


 最後に

なんでもかんでも一度に取り入れようと思うと、結果的に使い切れないことになりがち です。業務によって当然異なりますが、コンポーネント図や配置図はあまり使用するこ とがありません。まずは、プログラマーにとって非常に有用な、クラス図やシーケンス 図を作成してみてはいかがでしょうか。組み込み系の方には、状態図から取り組まれる のもお勧めだと思います。 本記事では、実際に図が描けるようになることを目的としましたので、UMLの用語や細部 の色々な仕様については、あまり触れないようにしました。この記事でUMLに興味を持っ ていただけましたら、必要に応じて他の記事や書籍なども参照してみてください。


 参考書籍

UML仕様書 ASCII
:Object Management Group 著
:OMG Japan SIG翻訳委員会 UML作業部会 訳




この記事への評価にご協力をお願いします。

良かった 普通 イマイチ