オブジェクトの広場はオージス総研グループのエンジニアによる技術発表サイトです

UML

Javaプログラマーに贈るUML入門

クラス図、シーケンス図、ユースケース図——必修ダイアグラムの使い方を学ぶ
(株)オージス総研
林田 幸司/藤田 和孝/永田 博靖
2004年11月4日

Javaのプログラミングに興味のある方であればオブジェクト指向やUMLといったキーワードに触れる機会が数多く存在するのではないでしょうか。最近ではオブジェクト指向によるシステム開発が多く存在するようになってきています。また、UMLに関してはオブジェクト指向技術による開発には欠かせない「道具」としてかなり注目されているのは事実です。これらの技術はJavaプログラミングに携わる方々にとって大きなメリットを与えてくれるものであり、必須の技術といって過言ではないでしょう。そこで、本記事によりJavaのソースコードとUMLの関係において最重要な部分を理解することにより、UMLとオブジェクト指向の導入としてもらいたいと思います。

※本稿は、雑誌『 Java WORLD 』 2004 年 5 月号に掲載された特集「Javaプログラマーに贈るUML入門」を加筆、修正したものです。Java WORLD 編集部の了承を得たうえで転載しています。

はじめに

UMLがここまで注目されるということはUMLというものをソフトウェアの開発に 使うことで何か良いことがあるのです。それはいったいなんでしょうか。最近 では一般的なソフトウェアの開発のみならず、様々な方面で使われ始めていま す。例えば、ビジネスの流れや構造をモデリングする「ビジネスモデリング」 や、データベースを中心とした業務システム開発のための「データモデリング」 等も面白い例です。つまり、UMLはそれほどの表現能力を備えているのです。 このように、UMLが注目されて、数多く取り上げられ普及してきた今日では、 ソフトウェア開発に従事するエンジニアや管理者の方はもう関わらずにはいら れない状況になってきていると言えるでしょう。

このように、UMLやオブジェクト指向に対する必要性や重要性は理解していて も、なんとなく難しい、どのように使えば良いのかわからない、学ぶきっかけ がない、などと感じて手をこまねいている読者の方もいらっしゃるかもしれま せん。しかしそのように構える必要はありません。UMLとはプログラミングを行 う際にその設計図を作成するための「道具」だと考えてください。

本記事ではUMLを深く知らない方々を対象として、UMLとはなんであるか、どの ように使うのか、そして、UMLを使うことによる効果などをオブジェクト指向 の考え方を少し取り入れながら説明していきます。主にはJavaのソースコード とUMLに用意される「図」の関係について説明していきます。実際のソースコー ドとUMLの具体的な関係を理解することにより、読者の皆さんはUMLが難しいも のではなく気軽に使える事に気付くでしょう。これにより、オブジェクト指向 の考え方を踏まえたプログラミングを始める足がかりとなり、さらにオブジェ クト指向の概念を学ぶことにより、オブジェクト指向言語であるJavaの本来の 実力を引きだせるようになります。そして、更にUMLとオブジェクト指向を用 いたプログラミングが手放せなくなるほど有益に感じられるようにもなり、プ ログラミングが楽しく分かりやすいものになっていくでしょう。

今回の記事では主にJavaのプログラミングの知識がある方を対象として書いて います。ただし、詳細な知識が必要なわけではなく基本的な文法が理解できる 程度で十分な内容です。

UMLとは?

さて、まずUMLとは何か、という点について簡単に学んでおきましょう。Java とUMLのマッピングを学ぶ上で最低限必要となる内容です。

「統一モデリング言語UML(Unified Modeling Language)」とは、一言で言うと 「ソフトウェアの設計図」を作成するための道具です。「言語」という名付け がされていますが、これはプログラミング言語のように実装、コンパイルを行 うものではありません。UMLでは数種類の「図」を用意していて、それらの 「図」を用いてソフトウェアやビジネスを図示することができます。言うなら ば、建築における家の設計図と同様のものと考えることが出来ます。

家を建てる際、大工さんがいきなり木材を元に家を建て始めるということは、 当然ながらありえず、依頼者がまずは建築の専門家などと相談をしながら要望 を確定していきます。そして、その後建築の専門家がその要望をどのようにし て実現するか設計図を書きます。その際、建築の設計図は書き方が決まってい ます。つまり、建築家や大工さんの間でその設計図を共有し、理解して家を作っ ていくことができます。

これと同様に、UMLを使うと、建築の場合と同様にソフトウェアを開発するた めの設計図を作成することが出来るのです。また、書き方(文法)が仕様として 定まっているため、開発者間で設計の情報を共有することも可能です。

ちなみにUMLの仕様を決めているのは、OMG(Object Management Group)という 非営利団体です。OMGは、1997年にUMLの最初のバージョンであるUML1.1を発表 しました。その後、UMLはバージョンアップとともに仕様が改定され、現在は UMML1.5が最新バージョンとなっています。

また、UMLの知名度について参考データですが、弊社オージス総研がUML普及の 目的で行っていたUML技術者認定制度は、受験者累積40万人という実績があります。 現在その認定制度も、2003年9月にNPOとして設立された「UMLモデリング推進 協議会(UMTP)」(参考URL https://www.umtp-japan.org/index.html )に移管され、 更にグローバルにUMLが展開されています。モデリング技能のレベルを問う試 験となっていますので、スキルアップのためにこの試験を目標にするというの も良いかもしれません。

UML 2.0

現在主に使われているUMLのバージョンは1.5だが、次のバージョンであるUML 2.0が、今年上半期中にも登場する予定となっている。

UML 2.0では、UML 1.5で問題になっているいくつかの部分が修正される。具体的には、新しいダイアグラムが追加されたり、既存のダイアグラムの表現能力が向上したりする予定だ。

こうした改善により、UML 2.0では、ソフトウェアの構造をより厳密に表現し、モデルとソース・コードの対応関係を明確に表せるようになる。その結果、上流の設計工程から下流の設計工程までの作業をUMLを使って行い、最後にツールによってUMLのモデルを基にしたプログラムのソース・コードを自動生成するといった開発が行えるようになる。このようなアプリケーション開発の構想を「MDA(Model Driven Architecture)」と呼ぶ。UML 2.0は、このMDAの実現に向けて策定された仕様だと言えるだろう。

なお、MDAの詳細については、本号の特集2を参照されたい。また、UML 2.0の仕様はOMGのWebサイト( https://www.omg.org/uml/ )で公開されているので、興味のある方はご覧いただきたい。

具体的にはどう使われる?

さて、UMLとは「ソフトウェアの設計図」の表記法を仕様化したものであるこ とは上述していますが、さらに詳しく言うと、主にJava言語等のオブジェクト 指向言語におけるクラス間の関係や、メッセージのやり取りを数種類の「図」 で表現し、理解し易くしてくれる「道具」です。実はこのように「図」で理解 するという方法は至極自然なことです。私たち人間は何か「複雑なもの」や 「複雑な事象」を理解しようとする場合、「図」によってビジュアルに考えよ うとしますよね。それと同様にソフトウェアの構造や動作を「図」で表現する ための「道具」がUMLなのです。理解しやすいことが目標ですから、当然UML に用意されている「図」の表記方法自体は難しいものではなく、表記の意味を 少し学べば誰でもUMLによるソフトウェアの設計図を読むことができるように なります。(以降、このUMLの「図」のことをダイヤグラムと呼びます。)

UMLが読めるようになるということは、ソフトウェア(プログラム)の構造や 処理の流れについて直接ソースコードを読まずとも、UMLのダイヤグラムによっ て、とても理解しやすい形で把握することができるようになります。これだけ でも大きなメリットだと感じらるでしょう。ソースコードを一から読み、全体 を把握するのはとても骨が折れますよね。更に、ある程度大きなソフトウェア ともなればソースコードのみから全体像を短時間で把握するのは不可能と言っ ても過言ではないでしょう。

ただし、一からソフトウェアを開発する場合は少し話が異なります。UMLによ る既存の設計図を読むということとは異なり、ソフトウェアの開発における 「分析や設計」を行う場合、当然、単にUMLのダイヤグラムを知っている、読 める、だけでは開発は出来ません。オブジェクト指向の概念や分析設計のノウ ハウによって設計図を作成するスキルが必要となります。つまり、UMLの表記 方法や意味を学んだからといってソフトウェアの開発全てが格段に簡単になる というわけではありません。

UMLとは単にダイヤグラムの表記方法やセマンティックスを仕様化しているも のだということが重要です。そのUMLをソフトウェア開発において上手く活用 するためには、「開発プロセス」や「開発方法論」といったノウハウを適切に 適用していく必要があります。それらプロセスや方法論、そして開発者のノウ ハウをもとにソフトウェアを分析、設計していきます。その際使用する「道具」 がUMLです。

開発プロセスとオブジェクト指向開発方法論

開発プロセスとは、システムの開発手順をまとめたものだ。具体的には、要件定義からシステムの導入、保守に至るまでの作業手順や、各工程で作成する成果物の雛型などを定義している。

一方、オブジェクト指向開発方法論とは、オブジェクト指向手法によって開発を行ううえでのルール(モデルの表記法など)や開発プロセスをまとめたものである。オブジェクト指向が考案された当初は、多くの開発方法 論が存在し、方法論ごとにさまざまな表記法が提唱されていた。しかし、時代の流れとともにそれらの表記法は淘汰され、現在ではUMLに統一されている。 最近のオブジェクト指向開発方法論としては、UMLと、「UP(Unified Prosess)」や「XP(eXtream Programming)」などの開発プロセスを組み合わせるケースが知られている。

さて、上述のようなソフトウェアの分析や設計のプロセスや方法論も大切なのですが、まずはUMLによって記述された設計図を読めるということが必要です。 ダイヤグラムの表記法について、Javaとのマッピングを踏まえながら本記事で しっかりと学んでください。

さて、それでは本題に入っていきましょう。

「書籍・雑誌管理アプリケーション」仕様

本記事では実際に動作するアプリケーションを元に、そのソースコードがどの ようにUMLにマッピングされるか説明していきます。使用するアプリケーション「書籍・雑誌管理アプリケーション」の仕様は以下の通りです。

−・−・−・−・−・−・−・−・−・−

このシステムは、社内の蔵書管理を行うためのWebアプリケーションです。社 内の蔵書情報を共有化するために、以下の3つの機能を実現しています。

  • 書籍・雑誌を登録する
  • 蔵書を検索する
  • 新着の書籍・雑誌を案内する

利用者は、Webブラウザから上記の全ての機能を利用できます。

「蔵書」は、一意に識別できるようにするため、管理番号を割り当てます。 「蔵書」には、和書と洋書がありますが、「書籍」と「雑誌」に大きく分類し ています。「書籍」は社員が任意に購入し、その際に書籍情報をWebアプリケー ションに登録するため、同じ「書籍」が複数登録されることがあります。「雑 誌」は会社で定期購読をしているため、重複して購入されることはなく、社内 で1冊のみ管理されます。

−・−・−・−・−・−・−・−・−・−

なお、このアプリケーションはダウンロードできます。あらかじめソースコードを確認しておきたい方は、ダウンロードしてご確認ください。

UMLが用意するダイアグラムについて

さて、上述のアプリケーションをUMLに置き換える前に、まずはUMLに用意され ているダイヤグラムの種類を見てみましょう。

UML(1.5時点)では以下の8つのダイヤグラムが用意されています。これらの図 はそれぞれ異なった視点と目的を持っており、ソフトウェア開発の適切な局面 においてそれぞれ使用していきます。ここではまずそれぞれのダイヤグラムを 大きな分類で括って紹介しています。大きく3つの分類に分けられます(図1)。

UMLが用意するダイヤグラムの種類 図 1 : UMLが用意するダイヤグラムの種類

モデリングの種類

オブジェクト指向によって何かを分析、設計、実装することを「モデリング」 と呼んでいます。そしてそのモデリングによって作成された成果物を「モデル」 と呼んでいます。(図1)では、そのモデルの種類ごとにUMLダイヤグラムを列挙し ています。

構造モデル

アプリケーションの静的な側面のモデルを「構造モデル」と呼んでいます。ク ラスやインターフェース、コラボレーション、コンポーネント、ノードなどの 静的な構造や関係を表現します。(図1)にあるように、クラス図、(オブジェ クト図)、コンポーネント図、配置図が使われます。

振る舞いモデル

アプリケーションの動的な側面のモデルを「振る舞いモデル」と呼んでいます。 時間軸に沿った処理の流れをモデリングします。オブジェクト同士の関係やメッ セージのやり取りや、あるオブジェクトの状態遷移、アルゴリズムなどの表現 が可能です。(図1)にあるように、シーケンス図、コラボレーション図、ス テートチャート図、アクティビティ図が使われます。

ユースケースモデル

開発対象のアプリケーションの振る舞いに関して全体的な視点から表現します。 細かい実現方法ではなく、アプリケーションがどのような機能を持っており、 どのようなユーザーと関係を持っているかについて表現します。ユースケース 図が使用されます。

さて、本記事では、上述のサンプルアプリケーションを用いてUMLとJavaソー スコードの説明を行います。今回はUMLのダイヤグラムとして特に重要な「ク ラス図」「シーケンス図」「ユースケース図」に関して取り上げて説明します。 この3つのダイヤグラムだけでも理解して読めるようになれば、UMLのメリット の多くを得ることが出来るようになるでしょう。

Javaソースコードと「クラス図」

皆さんは、プログラムを作成しているとき、全体の見通しの悪さに困ったことはないでしょうか。 例えば、あるクラス(クラスA)の中で、別のクラス(クラスB)のメソッドを 呼び出しているとします。このような場合に、クラスBのメソッドのパラメータを 変更したら、クラスAは当然その影響を受けてしまいます。したがって、クラスBを 変更する前に、クラスBを使っているのはどのクラスかといったことを調べる必要が あります。しかし、クラス間の関係を調べるのに、いちいちソースコードを読むの では骨が折れますね。そこで役立つのがクラス図です。

クラス図は、主にソフトウェアを構成するクラスの構造と、クラス同士の静的な 関係を表します。この図にクラス同士の関係が表されるのですから、それを見れば、 「クラスAがクラスBを使っている」ということが簡単に把握できるのです。

このクラス図によって、アプリケーション全体を見渡せるようになります。 全体を見渡したうえでソース・コードを読めば、その意味をより早く、正確に 理解できるというわけです。アプリケーションを構成するクラスの数が、50個、100個、200個と 増えた場合には、クラス図なしで全体の構造を把握するのは不可能に近いでしょう。 そのような理由から、クラス図は、UMLのダイアグラムの中でも最も重要であると言えます。

それでは、Javaソースコードを見ながら「クラス図」へのマッピングを理解し ていきましょう。「書籍・雑誌管理アプリケーション」の一部のソースコード をクラス図として表していきます。(なお、これより先の説明では、アプリケー ションを構成するクラスなどの情報を少しずつ使って説明をしていきます。)

書籍を表すBookクラスのソースファイルです(リスト1)。2つのフィールドと 1つのコンストラクタ、4つのメソッドが定義されています。これをUML にマッ ピングさせた図が(図2)です。クラス図おいて単一のクラスを表す場合、 (図2)のように三段に区切った矩形を使用します。つまり、この四角い図が Javaの一つのクラスと対応していて、全ての情報を持っているというわけです。 ただし、メソッド内のロジックは表現しません。

リスト1 : クラスBookのソースコード

public class Book {
   private String title; ...①
   private String isbn;
   public Book(String title,String isbn) {
      this.title = title;
   }
   public String getTitle() {
      return title;
   }
   public void setTitle(String title) {
      this.title = title;
   }
   public String getIsbn() {
      return isbn;
   }
   public void setIsbn(String isbn) {
      this.isbn = isbn;
   }
}

クラスBookを表すクラス図 図 2 : クラスBookを表すクラス図

さて、Java言語では文法として、フィールドとメソッドの記述は明確に定めら れています。「フィールド」であれば(リスト1-(1))のように、 「可視性 型 フィールド名」の順序で書かなければコンパイルは通りません。 UMLにおいてもその文法は決められています。フィールドの情報をクラス図に おける二段目の区画に表す際には以下の順序で記述します。

可視性 フィールド名:型=初期値

フィールド名と型の順番がJavaの定義方法とは異なるので気をつけてください。 なお、必要に応じて初期値が存在しなければ省略可能です。

「メソッド」に関しては、Java言語では(リスト1)の(2)のように「可視性 戻り値の型 メソッド名(パラメータ)」と定義します。それをUMLにマッピン グさせる場合には以下の順番で記述します。こちらもJavaとは定義の順番が異 なります *1

可視性 メソッド名(パラメータ):戻り値の型
*1 なお、本来UMLでは「フィールド」と「メソッド」に対応する項目を「属性」「操作」という用語を使用します。 本記事ではわかりやすさのため、全てJava言語の用語である「フィールド」「メソッド」という表現を使用しています。

フィールド、メソッド双方の定義で使用する「可視性」は表1の通りです。

表 1: 可視性の表記方法

可視性の表記方法

また、クラスは表示する要素を取捨選択することによっていろいろな形式で 表示することが出来ます。例えば、(図3)のように、フィールドの可視性と 型、メソッドの可視性とシグニチャ ( パラメータと戻り値 ) を省略して表記 することも可能です。(図4)のようにフィールド、メソッドの区画ごと省略 することも可能となっています。

可視性、シグニチャを省略したクラスBook 図 3 : 可視性、シグニチャを省略したクラスBook

フィールド、メソッドの区画を省略したクラスBook 図 4 : フィールド、メソッドの区画を省略したクラスBook

なお、例示はしていませんが、staticキーワードを使用したクラススコープの フィールドやメソッドには、該当するフィールドやメソッドの定義に対してア ンダーラインを付けて表現します。

クラス間の「関係」の表記について

次に、クラス間の「関係」について説明します。「関係」とはなんでしょう。 Java言語によってプログラミングを行う際、当然一つのクラスに全ての機能を 持たせることはありませんね。ある単位で機能(責務)の分担を行って、必要 な際に他のクラスのメソッドを使い、オブジェクト同士がコラボレーションし ながら一連の処理を実現します。そのようにコラボレーションする相手クラス とのつながりを「関係」と呼んでいます。

UMLで扱う「関係」には、関連、汎化、実現、集約、コンポジション、依存と いった種類が存在しています。継承を表すJava言語のextendsキーワードも 「関係」の一つです。ですから、一言で「関係」といっても様々な種類がある のです。上述の例のように、あるクラスがあるクラスを使う場合も「関係」が あるといいますが、そのような場合だけではなく、その「使い方」や「関係の 仕方」によって「関係」の種類が変わってきます。そして、その関係の種類を UMLで表記する方法である「線分の種類」が「関係」それぞれに用意されてい ます(図5)。適切な表記方法を使うことでクラス間の「関係」の種類を一目瞭 然に把握することができるようになります。

クラス間の「関係」の種類 図 5 : クラス間の「関係」の種類

それでは、「関係」の種類の定義と、それぞれのJavaソースコードへのマッピ ングについて見ていきましょう。

関連

「関連」関係とは、コラボレーションする相手のクラス(オブジェクト)をい つでも参照できる場合を表す関係です。(リスト2)を参照して下さい。Book クラスの(1)が示すフィールドにはContent型の変数が宣言されています。この ようにあるクラスの型をフィールドとして定義している場合は通常「関連」と して表現されます。このような関連が存在していれば、Bookクラスはいつでも 必要なときにdescription変数に対してgetMemo()と呼び出しを行うことで必要 な処理をContentクラスに任せることが出来ます。(リスト2)では、Bookの説 明文を返却するgetDescription()メソッド(2)の内部でdescription.getMemo() として使用しています。

リスト2:「関連」を表すソースコード

// クラスBook
public class Book {
   private String title;
   private Content description;
   …略…
   public String getDescription() {
      return description.getMemo();
   }
   public Book(String title, String memo) {
      this.title = title;
      this.description = new Content(memo);
   }
   public String getTitle() {
      return title;
   }
   public void setTitle(String title) {
      this.title = title;
   }
   …略…
}

// クラスContent
public class Content {
   private String memo;
   public Content(String memo) {
      this.memo = memo;
   }
   public String getMemo() {
      return memo;
   }
   public void setMemo(String string) {
      memo = string;
   }
}

さて、このBookクラスとContentクラスの「関連」関係をクラス図として表す と(図6)のようにマッピングされます。BookクラスからContentクラスに対し て矢印が引かれています。これは、BookクラスがBookクラスのフィールドとし てContent型のオブジェクトを保持しているという「関連の方向」を表してい ます。この矢印の方向を「誘導可能性」と呼びます。Bookクラス側に対して矢 印がないのは、ContentクラスがフィールドとしてBook型のオブジェクトを保 持していないことを示しています。つまり、単方向の関連です。Contentクラ スはBookクラスに対して何も処理の依頼をしないし、出来ないということにな ります。

「関連」を表すクラス図 図 6 : 「関連」を表すクラス図

(リスト2)のBookクラスはContentクラスのオブジェクトをフィールド名 descriptionとして保持しているのですが、そのdescriptionというフィールド 名は、クラス図においては関連端に示されているロール名としてマッピングし ます。UMLにおけるロール名とは、関連元クラスに対する関連先相手クラスの 役割を名前で表現したものです。そのロール名がJavaのフィールド名とマッピ ングしています。また、ソースコードにおいて、Content型のフィールドは privateとして宣言されています。この情報を示すために、UMLではロール名の 頭にprivateを示す可視性である「-」記号が付けられます。

そして、(図6)のクラス図ではContent側の関連端に「1」という数字が記述 されています。これは「多重度」と呼ばれる情報です。多重度とは、関連す るオブジェクトの個数を示します。つまり、Book型のオブジェクトが関連する Content型のオブジェクトの個数は必ず「1つ」であることを示しています。 (リスト2)のソースコードを見てみると、Bookクラスはリスト2−(1)に定義 されているように、Content型のフィールドであるdescriptionを1つのみ持つ 実装であることが確認できます。もし例えば、リスト2-(1)の実装が配列と してContent[]などと実装されている場合は、Bookオブジェクトは複数の Contentオブジェクトと関連することになり、多重度の数値も複数を示すよう になります。多重度の表現方法に関しては(表2)にまとめています。なお、 多重度が複数になる場合の例は、集約のところで説明します。

表 2: 多重度の例

多重度の例

誘導可能性

誘導可能性とは、関連のある2つのオブジェクト間の参照方向を表したものである。これは、「双方向」か「単方向」のいずれかとなる。

実際にシステム開発を行う場合、分析フェーズでは、2つのクラスの関連の誘導可能性を詳細に考える必要はない。しかし、設計フェーズでは、この誘導可能性をできる限り単方向にするよう心がけて設計する必要がある。その理由は、誘導可能性を双方向にすると、実装時に双方のクラスが互いの参照をフィールドに持ってしまうことになるからだ。これでは、一方を変更すると、もう一方にも影響を与えてしまうため、修正に非常に手間がかかってしまう。

ちなみに、UML 2.0では、表記の厳密性を高めるため、誘導可能性の定義の種類が増え、未定義である場合や、参照しないことを明示するための表記などが追加される予定だ。

汎化

汎化とは、より一般的なクラス(スーパクラス)とより特化したクラス(サブクラス)間の 分類上の関係を意味します。より特化したクラスはより一般的なクラスが持つ フィールドやメソッドを利用することになるため、汎化を実装する場合、 継承が利用されます。例えば、(図5)ではスーパクラス(A2)の「フィールドやメソッド」を サブクラス(B2)が引き継ぎます。

さて、Java言語における汎化関係はどのように実装していたでしょうか。(リ スト3)を参照してください。Publication、Book、Magazineクラスが定義され ています。書籍・雑誌管理アプリケーションでは、書籍と雑誌を管理するので それぞれBookとMagazineクラスが存在しています。両クラスは出版物として共 通の性格を持っていますので、その共通部分を括りだしたクラスを Publicationとして定義し、Book、MagazineクラスがPublicationクラスを継承 する構成としました。具体的にはリスト3-(1)、リスト3-(2)の部分です。

リスト3 : 「汎化」を表すソースコード

// 抽象クラスPublication
public abstract class Publication {
   private String title;
   private Content description;
   …略…
      protected Publication(String title, String memo) {
      this.title = title;
      this.description = new Content(memo);
   }
   …略…
}

// クラスBook
public class Book extends Publication {
   private String isbn;
   …略…
   public Book(String title, String memo, String isbn) {
      super(title, memo);
      this.isbn = isbn;
   }
   …略…
}

// クラスMagazine
public class Magazine extends Publication {
   private String issue;
   …略…
   public Magazine(String title, String memo, String issue) {
      super(title, memo);
      this.issue = issue;
   }
   …略…
}

さて、この3つのクラス間の汎化関係をクラス図で表現すると(図7)のように なります。スーパクラスであるPublicationクラスとサブクラスであるBook、 Magazineクラスの間に実線を引き、スーパクラス側の線の先に白抜きの三角形をつ けます。また、スーパクラス側にある白抜きの三角形を複数のサブクラスで共有する 表記方法も同じ意味で使用することができます(図8)。

「汎化」を表すクラス図(セパレート・ターゲット・スタイル) 図 7 :「汎化」を表すクラス図(セパレート・ターゲット・スタイル)

「汎化」を表すクラス図(シェアード・ターゲット・スタイル) 図 8 : 「汎化」を表すクラス図(シェアード・ターゲット・スタイル)

なお、先ほどBookクラスがその書籍の説明を表すContentクラスを関連として 保持していましたが、汎化を導入したため、PublicationとContentクラスの関連 に変更になっています。その関連は先ほどと同じようにロール名の頭に「-」 記号がついており、privateとしてフィールドで保持します。従って、汎化関 係にあるとはいえどBookは直接description変数にアクセスすることはできま せん。この場合Book型のオブジェクトからは、Publicationのpublicメソッド であるgetDescription()を介してdescriptionの情報にアクセスする必要があ ります。もしここで、Publicationクラスのフィールドに保持されるContent型 のオブジェクトの可視性がprivate(-) ではなく、protected(#)または public(+)として保持されている場合には「関係も継承される」ため、Bookや Magazineからdescription.getMemo()として直接アクセスできます。

(図7)のクラス図を良く見るとPublicationクラスのクラス名が「斜体」になっ ていることに気付きます。これは、Pulicationクラスが抽象クラスであること を示しています。Java言語で言うところのabstractキーワードで定義されたク ラスです。(リスト3)のPublicationの定義はabstruct classとして定義され ています。

汎化関係を使う場合、各クラスの構成を体系的把握しやすいこ とや、スーパクラスから特化した機能のみをサブクラスに実装すればよいという意味 で、差分プログラミングが可能である等、多くのメリットがあります。しかし、 スーパクラスに変更が発生した場合、サブクラスはその影響を受けやすい等、カプセ ル化が弱くなるデメリットも存在するため、フィールドやメソッドに設定する 可視性については考慮する必要があります。汎化を使用するか、または、関連 を使用するか適切に選択することが重要です。

カプセル化とポリモーフィズム

オブジェクト指向の重要な考え方に、「カプセル化」と「ポリモーフィズム(多様性)」がある。

カプセル化とは、データとそれを操作する手続きを一体化してモジュールという単位にまとめ、モジュール内の仕様や構造を外部から隠蔽することを指す。これは、簡単に言うと、「どの手続きを公開し、どの手続きを非公開にするか」を明確に切り分ける作業である。UMLでは、このカプセル化を実現するために、可視性を定義している。

一方、ポリモーフィズムとは、オブジェクトに同じメッセージを送ったとしても、受ける側のオブジェクトがそれぞれ独自のやり方でメッセージを処理し、異なる反応を示すことを指す。親クラスのメソッドをサブクラスで再定義を行える「汎化」あるいは「実現」を使えば、ポリモーフィズムのメカニズムをうまく実現することができる。

集約、コンポジション

「集約」関係とは、あるオブジェクトがもう一方のオブジェクトと「全体と一 部の関係にある」場合に使用します。また、コンポジションは集約の条件に加 え、2つのオブジェクトのライフサイクル(生存期間)も同じ場合に使用し、 強い集約関係を表します。

Java言語ではどのように実装される関係でしょうか(リスト4)。 PublicationCatalogクラスには(1)において、List型のフィールドである publications変数が定義されています。ArrayList型のオブジェクトで初期化 されており、その要素として(2)(3)のメソッドを使ってPublication型のオブ ジェクトが格納されたり、取り出されたりします。つまり、 PublicationCatalogクラスはフィールドにPublication型のオブジェクトを複 数保持しているということになります。また、ソースコードからは読み取れな いですが、アプリケーションの立場から見ると、PublicationCatalog(出版物 カタログ)クラスはPublication(出版物)を管理する「全体」のクラスとし て抽出されています。逆にいうと出版物は出版物カタログの「一部」として存 在しています。このように「全体と部分」の意味的な関係があることを「集約」 と呼んでいます。

リスト4:「集約」を表すソースコード

// クラスPublicationCatalog
public class PublicationCatalog {
   private List publications = new ArrayList();
   public String addPublication(Publication publication) {
   …略…
   }
   public Publication getPublication(String id) {
   …略…
   }
}

// 抽象クラスPublication
public abstract class Publication {
   private String id;
   private String title;
   …略…
}

このようにpublication変数をフィールドとして保持するということは、「集 約」の実装方法は、上述の「関連」と同様であることに気付くと思います。こ れはまさにその通りです。実はJavaソースコード上では「関連」と「集約」に 違いはありません。意味的に「全体と部分」の関係を示したものが「集約」で す。つまり、関連の中でも、概念的に全体を表すクラスが一部を表すクラスを インスタンス変数としてフィールドに保持する実装の場合が、「集約」関係だ ということになります。更に「コンポジション」の場合は、参照するクラスの ライフサイクルについても、自分と同じになるように責任を持って管理するよ うな場合が該当します。

さて、このような「集約」関係をクラス図として表現した場合を見てみましょ う(図9)。単純な「関連」とは異なり、ひし形の図形が「集約している側」 に付けられます。PublicationCatalog(出版物カタログ)クラスと Publication(出版物)クラスの関係が、意味的に「全体と部分」の関係であ ることを示していることになります。繰り返しになりますが、「集約」はこの ように意味的なものであるため、Javaのソースコードの情報からは「関連」であ ることしか読み取れません。(今回は説明上「集約」としてマッピングを紹介 しました。)

「集約」を表すクラス図 図 9 : 「集約」を表すクラス図

続いて、(リスト4)を再度参照してください。PublicationCatalogクラスで は、ArrayListでフィールドpublicationを定義しています。したがって、 Publication型オブジェクトを格納可能な個数に上限はありません。その場合、 クラス図では、PublicationCatalog型オブジェクトに対するPublication型のオ ブジェクトの多重度として「」または「0..」と表現します。(ただしこの場 合でも、アプリケーションの仕様で保持するオブジェクトの数が決定されてい る場合は多重度の上限も指定されます。)

ArrayList型ではなく配列等を用いてこの関係をを実装しているような場合を 考えた場合、配列には上限値が存在するので、例えば「0..5」(0から5)とい うように明示的に取り得る範囲を多重度で記述することになります。

多重度と限定子の関係

(リスト4と図9)では、一つのオブジェクトに対して複数のオブジェクトが関 連を持つような場合を紹介しました。そして、配列を用いた場合は多重度が上 限値を持つ表現方法になることも説明しました。

ではさらに、ArrayListクラスや配列ではなく、HashMapクラスなどのキーと値 の関係でオブジェクトを管理するコレクションクラスを用いて複数のオブジェ クトを保持する実装を行う場合、UMLではどのように表現されるでしょうか。 まず、HashMapクラスで実装した場合のソースコードを参照してください(リスト5)。 (1)が示すようにPublicationCatalogクラスのフィールドは、複数 のBookオブジェクトをHashMapのオブジェクトに格納しています。キーはBook オブジェクトのISBN番号です。BookオブジェクトはPublicationCatalog オブ ジェクトに対して複数存在しているので、本来は上述の通りBookクラス側の多 重度は「」または「0..」となります。しかし、この実装の場合ISBN番号を キーとしてBookオブジェクトを一意に識別できることになります。したがっ て、、PublicationCatalogオブジェクトに対して、あるISBN番号を持つBook オブジェクトが「存在するか、しないか」という関係になります。その結果、 Bookクラス側の多重度は0か1に決定されます。

リスト5:クラスHashMapで実装したソースコード

// クラスPublicationCatalog
public class PublicationCatalog {
   private Map books = new HashMap();
   …略…
   public Book getPublicationByISBN(String isbn) {
      Book book = (Book)books.get(isbn);
      return book;
   }
}

// クラスBook
public class Book {
   private String isbn;
   …略…
}

このようにキーと値の関係でオブジェクトを管理するコレクションクラスを 用いる場合、UMLでは「限定子」という表記法を用いて表現します(図10)。 PublicationCatalogクラス側の関連端に矩形を一つ追加し、その内部にBook オブジェクトを一意に識別するキーである、String型のisbnという情報を記述 します。そして、Bookクラス側の多重度は「0..1」または「0,1」を指定しま す。

「限定子」を表すクラス図 図 10 : 「限定子」を表すクラス図

このように「限定子」は、関連するオブジェクトを何らかのキーによって一意 に決定し、その結果多重度を減らすことが可能です。

実現

「実現」関係とは、シグネチャのみで定義された実装の無いインターフェース とそれを実装するクラスとの関係です。まず、「実現」関係を実装したJavaソー スコードを見てみましょう(リスト6)。PublicationCatalogDAOインターフェー ス、PublicationCatalogDAOImplクラスが定義されています。これらは、図書・ 雑誌管理アプリケーションの出版物のデータを永続化するために作成している クラスです。

リスト6:「実現」を表すソースコード

// インタフェースPublcationCatalogDAO
public interface PublcationCatalogDAO {
   public void init() throws Exception;
   public void load(PublicationCatalog catalog) throws Exception;
   public void save(PublicationCatalog catalog) throws Exception;
}

// クラスPublicationCatalogDAOImpl
public class PublicationCatalogDAOImpl
   implements PublcationCatalogDAO {
   public void init() throws Exception {
      // 実装を行う
   }
   public void load(PublicationCatalog catalog)
      throws Exception {
      // 実装を行う
   }
   public void save(PublicationCatalog catalog)
      throws Exception {
      // 実装を行う
   }
}

PublcationCatalogDAOインタフェースはinterfaceキーワードで定義されてお り、3つのメソッドのシグニチャのみが定義されています。interfaceなのでロ ジックは持っていません。そして、そのインターフェースを実装するクラスが PublicationCatalogDAOImplクラスです。リスト6の(1)においてimplements としてインターフェースを実装する定義が行われています。そして、インター フェースに定義された三つのメソッドの実装が行われています。実装部分は省 略しましたが、このPublicationCatalogDAOImplクラスが永続化されたデータ の実際の読み出しや書き出しを行います。

さて、この「実現」関係をクラス図で表現してみましょう(図11)。インター フェースであるPublicationCatalogDAOクラスと実装クラスである PublicationCatalogDAOImplクラスの間に波線を引き、インターフェース側の 波線の先に白抜きの三角形をつけます。UMLにおけるインターフェースクラス の表記方法は二つあります。(図11)のように「ステレオタイプ <<interface>>」と明記するか、または、(図12)のように「ロリポップ」と 呼ばれる丸い記号で表します。クラス図においてロリポップ記号で表現する場 合には、インターフェースと実装クラス間を波線と白抜き三角で結ぶのではな く、実線のみでつなぐ違いがあるので注意してください。

ステレオタイプによって「実現」を表すクラス図 図 11 : ステレオタイプによって「実現」を表すクラス図

ロリポップによって「実現」を表すクラス図 図 12 : ロリポップによって「実現」を表すクラス図

ステレオタイプ

ステレオタイプとは、すべてのダイアグラムの要素に共通して付加できる拡張情報である。ステレオタイプを表記するには、<<と>>の間に付加したい情報を記入する。ステレオタイプは、ダイアグラムの要素を、内容によってカテゴリー分けしたいときなどに有効である。例えば、MVC(Model-View-Controller)モデルに対応するクラスに適切なステレオタイプを付加して、各クラスの役割を把握しやすくするといった使い方が考えられる。

抽象クラスとインタフェースの使い分け

抽象クラスもインタフェースも、ポリモーフィズムを実現するためには非常に有効な手段だ。ただし、それらをいざ使用する段階になって、どちらを使えばよいのかで迷った経験はないだろうか。ここでは、その際の判断基準となるポイントを紹介する。

  • 多重継承の観点から

    抽象クラスは、その名前からもわかるようにクラスの一種であり、それをスーパクラスとして使う場合、そのサブクラスではextendsキーワードを使用する。ここでのポイントは、Javaは多重継承をサポートしていないという点である。つまり、サブクラスは、複数の抽象クラスを継承できないのだ。

    一方、インタフェースはどうだろうか。インタフェースの場合、implementsキーワードを用いることで、複数のインタフェースを実装したクラスを作ることができる。したがって、オブジェクトに複数の役割を持たせたいような場合には、インタフェースが有効だと言える。

  • コード実装の観点から

    抽象クラスには、一部の実装を持たせることができるが、実装されていない操作はサブクラスで実装しない限り、サブクラスも抽象クラスとなってしまう。よって、実装を含み、継承されることを前提としたクラスを作成するような場合は、抽象クラスを使うとよい。

    逆に、インタフェースに定義できるのはメソッドのシグネチャのみであり、実装を持たせることはできない。よって、メソッドのシグネチャのみを公開し、実装はすべて別クラスで行うことを前提とする場合は、インタフェースを使ったほうがよいだろう。

  • 使い分けの考え方

    このほかにも、抽象クラスとインタフェースを使い分けのためのさまざまな判断材料があるが、ここでは割愛する。大まかにポイントをまとめると、抽象クラスは抽象的なものや概念を表すためのものであり、インタフェースは機能や役割、責務などを表すためのものだと考えればよいだろう。

依存

「依存」関係とは、依存先オブジェクトの変更が、依存元オブジェクトに影響 を与える可能性のある関係のことを示します。関連や集約、汎化等の他の関係 に属さない関係のことを「依存」関係という場合もあります。しかし、それで は漠然としすぎているため、具体的にどのようなJavaによる実装が依存関係と して表現するのか紹介しましょう。大きくは、依存先のクラスを以下の2つの 要素として扱う場合、2つのクラスの関係が「依存」関係に該当します。

  • (a)メソッドの引数、戻り値
  • (b)ローカル変数

(図5)におけるクラスA6とクラスB6の関係が「依存」関係の表記方法です。 依存する側のクラス(B6)から依存される側のクラス(A6)に対して破線矢印を 引きます。(a),(b)ともに「依存」関係としてこの表記方法を用います。Java のソースコードによって(a)、(b)の実装を示したのが(リスト7,8)です。

リスト7:「依存」を表すソースコード(メソッドのパラメータ、戻り値として依存)

// クラスA6
public class A6 {
   public void foo() {
      …略…
   }
}

// クラスB6
public class B6 {
   public void var(A6 a) {
      a.foo();
   }
}

リスト8:「依存」を表すソースコード(ローカル変数として依存)

// クラスA6
public class A6 {
   public void foo() {
      …略…
   }
}

// クラスB6
public class B6 {
   public void bar() {
      A6 a = new A6();
      a.foo();
   }
}

なお、クラス図ですべての依存関係について、表記を行った場合、非常に多く の依存関係が存在する場合があります。この場合、ビジュアルに表現すること でわかりやすくするというUMLのメリットを損なう可能性があります。そのよ うな場合には、意味的に重要な依存関係以外についてはクラス図から省略する ようにしましょう。これは、クラス図に限った話ではありません。図を作成す る場合は、その一枚の図によって何を示したいのか、という「図の目的」を明 確にして必要な情報のみ表記し、わかりやすい図を作成するということが重要 です。

Javaソースコードとシーケンス図

アプリケーションは複数のオブジェクトがメソッドを呼び出してコラボレーショ ン行います。メソッド呼び出しの相手がどのオブジェクトで、どんなタイミン グ、順番でメソッドを呼び出すのか、という情報を得るためにはソースコード を隈なく追っていく必要があります。とてもわずらわしい作業です。そのよう なソースコードを追う作業を軽減してくれる図がシーケンス図です。

シーケンス図は相互作用図の一種であり、主にアプリケーションの動的な流れ を表現することが可能です。やはりクラス図と同様に全ダイアグラムの中で重 要度が高いダイヤグラムです。

シーケンス図の表記について

(リスト9)では、PublicationCatalogクラスの定義がされています。このク ラスには(1)(2)の2つのメソッドが定義されています。また、Map型のフィー ルドbooksがHashMap型で初期化されており、booksに対して(2)のメソッド内 でメソッド呼び出しを行っています。

リスト9:クラスPublicationCatalogのソースコード

// クラスPublicationCatalog
public class PublicationCatalog {
   private Map books = new HashMap();
   …略…
   public String addPublication(Publication publication) {
      …略…
      if(publication instanceof Book) {
         addBook((Book)publication);
      }
      …略…
      return somethingString;
   }
   private void addBook(Book book) {
      String isbn = book.getIsbn();
      books.put(isbn, book);
   }
}

それでは、このPublicationCatalogクラスのメソッド呼び出しの流れをシーケ ンス図で見てみましょう(図13)。

書籍の登録処理を表すシーケンス図 図 13 : 書籍の登録処理を表すシーケンス図

(図13)と(リスト9)では書籍登録を行う処理を示しています。具体的には、 Clientクラスのオブジェクトから出版物の追加を行う際の操作の流れを確認し ます。まずClientオブジェクトは、Bookクラスを生成しています。次ぎに ClientオブジェクトはPublicationCatalogクラスの addPublication(Publication publication)メソッドを呼び出します。図では、 Clientから下された波線から、PublicationCatalog (PublicationCatalogクラ スのインスタンス)から下された波線に対して、水平に矢印がひかれているこ とがわかります。次にPublicationCatalogは、その呼び出しを受け、引数の publicationをPublication型からBook型にキャストを行った後、そのbookオブ ジェクトを引数にして、自分自身が持つメソッドaddBook(Book book)を呼び出 しています。この再帰呼び出しは、シーケンス図では、入れ子の表現として自 分自身へ返る矢印で示します。図のように、その処理範囲に合わせて長方形も 付加すれば、どのメソッドの処理中であるのか厳密に明示できます。次に、 PublicationCatalogのaddBook()処理中に、Book型のbookオブジェクトに対し て、getIsbn()メソッドを呼び出していることがわかります。getIsbn()メソッ ドを呼び出し、Book型のbookオブジェクトが持つISBN番号を取得して、それを キーにしてHashMapのコレクションに挿入しています。その後、Clientのメソッ ドに処理が戻ることが表現されています。なお、その処理後にClientは消滅し ています。

上述の説明の段落の情報のほとんどが(図13)のシーケンス図一枚に収められ ています。ビジュアルな表現は、いかに沢山の情報を含むことができるか実感 できるでしょう。

さて、ここでシーケンス図の表記方法を詳しく説明します。シーケンス図では、 主にオブジェクトを横方向に羅列します。そして、それぞれのオブジェクトか ら縦方向にライフラインと呼ばれる破線を引きます。縦方向は時間軸を表し、 下へ行くほど時間が経過することを表します。そしてライフライン間を垂直に 結ぶように上から順番にメッセージを表す矢印を付加します。こうすることで、 時間に沿ったオブジェクト間のメッセージのやり取りが表現できます。

シーケンス図の表記に関する要素およびJavaとのマッピングについて、さらに 細かく説明します。

(1)オブジェクトの表記について

オブジェクトとはクラスのインスタンスです。オブジェクトの表記方法は、矩 形内に以下のラベル情報を記述し、その情報にアンダーラインを引きます。コ ラボレーション図やオブジェクト図においても同様にオブジェクトを表現します。

オブジェクト名:パッケージ名::クラス名

なお、(図13)においては、パッケージ名は省略して表記しています。また、 Clientはオブジェクト名のみを表記しており、また、PublicationCatalogおよ びBook は、オブジェクト名を省略してクラス名のみの表記となっています。

(2)ライフラインの表記について

ライフラインは、オブジェクトが生成されてから消滅するまでの期間を表します。 つまり、オブジェクトはライフラインが続く期間だけ存在し、下端のXマークの 時点で消滅します。Javaでは、オブジェクトはnewキーワードによって生成され、 メモリ領域から開放されるタイミングで消滅します。つまり、参照されることが なくなり、ガーベジコレクションの対象になった時点で消滅するのです。

(3)活性区間の表記について

活性区間はライフライン上に長方形を延ばして表現し、「呼び出されたメソッ ドが処理されている期間」を表現します。Java言語による実装では、処理され る「メソッドが呼び出された時点からメソッドが終了するまでの期間」にマッ ピングされます。活性区間の表記は省略することが可能です。

(4)メッセージとメッセージラベルの表記について

メッセージとはオブジェクトのメソッドを呼び出すことです。「メッセージを 送信する」や「メソッドを呼び出す」などと表現したりします。表記方法は、 オブジェクトのライフライン間に引いた「矢印」の上にメッセージラベルを記 述します。以下の記述のルールに従います。

シーケンス番号:戻り値:=メソッド名(引数並び)

メソッド名以外は、必要に応じて省略しても問題ありません。戻り値やメソッ ド名、引数の情報は全てクラス図に含まれる静的な情報です。

シーケンス図では上から下に向かって時間が経過します。つまり、シーケンス 図を上から下へ読み進めていけばメソッドが実行される順番が理解できるとい うことです。シーケンス番号はその順番を明示的に表記した情報です。シーケ ンス番号は明示しなくても、シーケンス図では上から下へ向かって順番にメッ セージ呼び出しが行われてることが自明ですので、シーケンス番号は省略可能 です。

次にメッセージの種類を考えてみましょう。(図13)では一種類のメッセージ のみを使用した例でしたが、実はメッセージには表3の3種類が存在し、メソッ ドの呼び出し方に応じて適切な表記を使います。

表 3: メッセージの種類
メッセージの種類

クラス図とシーケンス図の関係

クラス図は、ソフトウェアの静的な構造を表現する。したがって、ソフトウェアの動的な処理の流れ表現するシーケンス図とは“表裏一体”の関係にある。つまり、この2つのダイアグラムを使ってさまざまな情報を収集することで、ソフトウェア全体の構造を把握できるのだ。

ソフトウェア開発をスムーズに進めるためには、クラス図とシーケンス図の整合性を確認しながら、分析/設計を行うことが重要となる。この整合性を確認する作業は、具体的には、次の点に着目して行う。

  • シーケンス図に表記したオブジェクトを、クラス図にも表記しているかどうか
  • シーケンス図に表記したオブジェクト間のメッセージを、クラス図にもクラス間の関係として表記しているかどうか
  • シーケンス図に表記した「メッセージを受け取ったオブジェクト」を、クラス図にも表記しているかどうか。また、そのメッセージを処理するメソッドを表記しているかどうか
  • シーケンス図に表記したメッセージの方向(単方向か、双方向か)が、クラス図に表記したクラス間の関連の誘導可能性と一致しているかどうか

コラボレーション図

コラボレーション図は相互作用図の一種であり、シーケンス図と同じ情報を表現することができる。この2つのダイアグラムの違いは、シーケンス図が時間の経過を中心に表現するのに対し、コラボレーション図はオブジェクト間のリンクを中心に表現するという点にある。

ユースケース図とユースケース記述

ここまでクラス図、シーケンス図を説明してきました。これらのダイヤグラム はアプリケーションの内部の静的な構造や動的な流れを表現可能でした。これ から説明するユースケース図は、「アプリケーションの外から見た機能や動作 について表現」することが可能です。つまり、アプリケーション全体の仕様に 関して記述するダイヤグラムです。したがって、ソースコードからはこのユー スケース図はそのままマッピングするものではないという部分で他のダイヤグ ラムと性質が異なっています。

例えば、既にJava言語でプログラミングされたあるアプリケーションが存在し ていたとします。そのアプリケーションがどんな機能を持っていて、どんな動 作をするかといった「ユーザーの視点からのアプリケーションの機能」を知り たい場合、まずは実際に起動して動かしながら理解するか、または、アプリケー ションの機能や使い方が記されたドキュメントを参照するのではないでしょう か。その説明書や仕様書と言うべきドキュメントにあたるのがユースケース図 だと考えてください。

ユースケース図

まずは今回サンプルとして用いているアプリケーションをユースケース図に表 したものを見てみましょう(図14)。

書籍/雑誌管理アプリケーションを表すユースケース図 図 14 : 書籍/雑誌管理アプリケーションを表すユースケース図

ユースケース図はとても簡単な図であることがわかります。本記事冒頭に載せ ている「書籍・雑誌管理アプリケーション」の仕様を読み返してユースケース 図と見比べてみてください。ユースケース図に記述されている3つの楕円がこ のサンプルアプリケーションが提供する機能を表していることがわかります。 「出版物を登録する」「出版物を検索する」「新着の出版物を照会する」の3 つがアプリケーションが提供する「ユースケース」と呼ばれる機能です。それ ら楕円型のアイコンのユースケースは書籍・雑誌管理システムと名付けられた 「システム境界」と呼ばれる四角い領域に囲まれています。このシステム境界 はアプリケーションの領域を明示しています。逆にいうとこの四角い領域の外 側はアプリケーションの範囲外だということです。そして、それぞれのユース ケースは線分によって社員と名付けられた「アクター」と呼ばれる人型のアイ コンと関連付けられています。アプリケーションの範囲外である社員がこれら ユースケースと呼ばれる機能からサービスを受けるというとことを示していま す。なお、アクターはアプリケーションを使用する人だけではなく、アプリケー ションが依存する外部の既存システムも候補となり得ます。

このように、ユースケース図では、アプリケーションが提供する機能をユース ケースとして表し、そのユースケースを利用するユーザーやシステムなどを アクターとして表します。そうすることで、アプリケーションの全容をビジュアルに 表現するのです *2

*2 ユースケース図の記法については、ユースケースやアクターの汎化など更に高度な表現も用意されています。それらを用いると、アプリケーションの仕様をさらに構造的に表すことができます。

今回は、説明の都合上、既存のアプリケーションをユースケース図として表すと どうなるか、という流れで紹介しました。しかし、実際の開発では、要件定義の段階でこのユースケース図を作成します *3。ユースケース図は、開発対象のアプリ ケーションに要求される機能などを洗い出すときに使います。具体的には、アプ リケーションの利用者などの外部要素をアクターとして定義します。そして、 アクターから利用できるアプリケーションの機能を洗い出し、その機能をユースケースとして定義して、関連するアクターと線分でつないでいく、という作業を行います。

*3 開発において、どのタイミングでどのような作業を行いどんなダイヤグラムを 成果物として作成するかについては、採用する開発プロセスに関係してきます。

ユースケース記述

ユースケース図に示されるのは楕円と人型アイコンとそれに対する簡単な説明 のみですから、このユースケース図だけでは、要件を十分に細かく定義するに は不十分であることが予想できるでしょう。実は、ユースケースの肝はこのユー スケース図ではなく、そのユースケースの定義を行う「ユースケース記述」と 呼ばれる文書にあります。

ユースケース記述とはユースケース図の中の1つのユースケースについて、ア クターとアプリケーションとのやりとりをストーリーの流れとして書いたもの です。(図15 ユースケース記述)を参照してください。

「出版物を登録する」ユースケース記述の例 図 15 : 「出版物を登録する」ユースケース記述の例

書籍・雑誌管理アプリケーションの1つのユースケースである「出版物を登録す る」ユースケースに関しての詳細な処理ステップを記述しています。ユー スケース名、ユースケースの概要、関連アクター、基本フロー、代替フロー、 によって構成されていますが、実はユースケース記述の文法は明確に定義され てはいません。また、このユースケース記述自体もUMLの仕様として定義され ているものでもありません。ですから、実際には自由に記述してもかまわない ことになります。ただし、ユースケース記述としての目的は満たす必要があり ます。アプリケーションのユーザの視点からユースケースが動作するステップ を記述します。基本フローにはその機能の一番正常に流れるメインのステップ を記述します。アクターとアプリケーション(システム)が交互にやり取りさ れているのがわかると思います。処理が分岐する場合には代替フローにステッ プが移ります。(図15)では省略していますが、ユースケース記述 には事前条件(ユースケースを実行するのに満たしておくべき条件)や事後条 件(ユースケースが終了する際に満たされている条件)などを明記しておいた りもします。また、更に詳細に分岐などそのユースケースが取り得る全てのス テップを見つけ出して記述することが必要となります。このようにアプリケー ションとアクター間の対話のステップを記述することで、アプリケーションの 機能をユーザーの視点からとらえることができるようになります。

実際のソフトウェア開発では、ユースケースの定義内容を基に、クラス図やシー ケンス図を活用しながら、分析/設計を行うことになります。また、ユースケースの 数を基に、開発スケジュールやコストを見積もったり、ユースケースごとに作業を 分担して開発を進めたりします。さらに、ユースケースを基にして、テストケースを 作成することもあります。このように、開発工程全体にかかわってくるユースケース を表せるユースケース図は、UMLのダイアグラムの中でもとても重要な地位を占めて いるのです。

ユースケース図やユースケース記述を作成する際のポイントは、アプリケーションを 使用する「ユーザーの視点」で考えることです。ですから、この時点で実装方法など の実現方法の詳細については考えません。開発対象のシステムやアプリケーションが アクターに対してどのようなサービスを提供するかという点に関して関心を持って 作成するのです。つまり、アプリケーションはそれを使用するユーザーのために開発 されるため、そのユーザーの立場になって考えることは非常に重要なことだというこ とです。

アプリケーションの全体像

クラス図、シーケンス図、ユースケース図の表記法とそれらダイヤグラムに対 するJava言語との関係について説明をしてきました。UMLが用意するダイヤグ ラムの内3つのダイヤグラムのみの説明をしてきましたが、これらは最もよく 使われるダイヤグラムです。ですから、ここまで本記事で説明した内容を理解 し、UMLのダイヤグラムをJava言語との関係を踏まえて読解できるようになれ ば、UMLのメリットを十分享受することが出来るはずです。

ここまでの説明ではサンプルである図書・雑誌管理アプリケーションのJava ソースコードから、部分的にクラスの構成などを紹介してきました。部分のみ の紹介であったため、全体を理解することは出来なかったと思います。ここで、 図書・雑誌管理アプリケーションの全体像を確認してみたいと思います。全体 をUMLでビジュアルに表すことにより、アプリケーションをどのように理解で きるか確認をしていきましょう。

(図16)は、図書・雑誌管理アプリケーションの機能を実現する中心的なクラ ス群のみを表したクラス図です。各クラスのコンストラクタやgetter/setter メソッドなどは一部省略しています。これまでに順を追って説明してきた以下 の6つのクラスの関係を一つのクラス図中で表現しています。

アプリケーション全体を表すクラス図 図 16 : アプリケーション全体を表すクラス図

  • Contentクラス
  • Bookクラス
  • Magazineクラス
  • Publicationクラス
  • PublicationCatalogクラス
  • PublicationCatalogDAOインタフェース

各ダイヤグラムの説明時に使用したクラス図では、わかりやすさのために細か い情報は省略していましたが、図16では詳細なフィールドやメソッドも追加し ています。

先ほどまでの説明では、Javaのソースコードからクラス図にマッピングしてい ました。ここでは、逆にクラス図の定義からJavaのソースコードがイメージで きるでしょうか。もし、Javaソースコードがイメージ出来るようであれば、読 者の皆さんはたった一枚のダイアグラムから、複数のクラスファイルに定義さ れているJavaのクラスの全体の構造を理解できるようになっているということ です。それも短時間で理解できるはずです。例えば、以下のような情報がダイ ヤグラムから得られるのではないでしょうか。

  • PublicationクラスはBookクラスとMagazineクラスの共通部分を抽出したクラスである
  • PublicationCatalogクラスはPublicationクラスを管理する関係にある
  • PublicationCatalogクラスは、isbn番号をキーにしてBookクラスを管理する
  • NewArrivalクラスは、最大5冊のPublicationクラスを新着出版物として管理する
  • Publicationクラスは定価の金額を表すMoneyクラスを保持する
  • Moneyクラスは「円」と「ドル」を区別するためのCurrencyクラスを保持する
  • 出版物は、出版物の情報を表すPublicationクラスと、登録される出版物そのものを表すPublicationItemクラスによって表現される

(実際のJavaのソースコードとの対応関係については、ソースコードをダウンロードし、そちらと照らし合わせてみてください。)

こうした情報を、UMLで作成したモデルによって共有することで、開発者同士 のコミュニケーションが円滑になるでしょう。

さて次に、図書・書籍管理アプリケーションの処理の一部である「書籍を登録 する」部分の流れをUMLで表現してみます。オブジェクト間のメッセージのや り取りをこれまでに学習した表記法を用いてシーケンス図で表します(図17)。 クラス図に定義されていたPublicationCatalog型のオブジェクトやBook型のオ ブジェクトの間でメッセージがやり取りされています。書籍(bookオブジェク ト)が出版物カタログ(PublicationCatalogオブジェクト)に登録されている 流れがすばやく理解できるのではないでしょうか。このように、シーケンス図 においても実際にJavaのソースコードを調べずにオブジェクト間の処理の流れ を理解することができます。

書籍を登録する処理を表すシーケンス図 図 17 : 書籍を登録する処理を表すシーケンス図

(図17)では簡単な処理の流れを示しています。このシーケンス図では、 複雑な処理は行っていないのでダイヤグラムによる表記のメリットを感じにく いかもしれません。しかし、例えばさらに多くのオブジェクト間で膨大なメッ セージのやり取りが行われるようなアプリケーションの場合、ソースコードから 全体を把握するにはとても骨が折れます。そのような場合にはやはりビジュアルな シーケンス図の表現能力が実力を発揮するのです。

ただし、クラス図、シーケンス図を含んだ全てのUMLダイヤグラムの作成に当 てはまることですが、UMLで何かを表現するときはソースコード上で定義され ている(または、定義したい)情報全てをダイヤグラムに詰め込もうとするの は避けるべきです。例えばクラス図においては、全てのフィールド、メソッド、 関連などを書き込んだり、シーケンス図においては、実装のロジックを全て含 めるような詳細な表現がされているダイヤグラムがしばしば存在します。こ れでは、とてもビジュアルで読みやすいとは言えなくなり、UMLのメリットを 損なってしまいます。このように全ての(多くの)情報を一つのダイヤグラム にまとめて表記すると、そのダイヤグラムが示したい重要な情報がぼやけてし まい、結局読み手に何を伝えたいのかわからなくなってしまうのです。UMLを 利用する際のとても重要なポイントは、誰に対して、どのレベルで、何を伝え たいか、といった目的を明確にしたダイヤグラムを作成することです。目的に 従って、必要な要素のみを表記し読み手が理解しやすいダイヤグラムを作成す るように心掛けましょう。

おわりに

まずはJavaソースコードとUMLのマッピングから学びましょう、ということで 説明してきましたが、ご理解いただけたでしょうか。今回はUMLにおいて重要 なダイヤグラムとして、「クラス図」「シーケンス図」「ユースケース図」を ご紹介ました。特にJavaプログラマーの方にとっては、クラス図とシーケンス図 が強力な武器になるはずです。

今回は既存のアプリケーションからUMLへマッピングを示しながらの説明を行 いました。これは、実際のソフトウェア開発の流れとは逆となります。実際に は、開発プロセスに則り、要求、分析、設計、実装、テストといった流れで開 発は進められます。そしてUMLは分析や設計時に使われ、実装時にはそのUMLの 設計図を見ながら実装するのです。したがって、今後は開発プロセスにおいて UMLが使用されるタイミングと目的といった点に着目してUMLを学ぶことで、効 果的に身に付けることが出来ると考えています。

本記事によって、UMLとJavaのマッピングを理解出来たと思いますので、今後 はUMLを用いて分析や設計を行ってからプログラミングを行うことに挑戦して みてください。小さなアプリケーションを作成する場合にも、直接プログラミ ングを行うより明らかに見通しがよく修正がし易い、良いアプリケーションを 作成できることに気付くでしょう。また、オブジェクト指向的な考え方を養う ためにも、UMLによって様々なモデルを作成することで徐々に慣れていってい ただければと思います。

《参考文献》

  1. 「UMLモデリングのエッセンス 第2版」
    著者:マーチン・ファウラー、ケンドール・スコット
    発行:翔泳社, 2000
  2. 「UMLユーザガイド」
    著者:グラディ・ブーチ
    発行:ピアソン・エデュケーション, 1999
  3. 「Javaプログラムデザイン 第3版」
    著者:戸松 豊和
    発行:翔泳社, 2002
  4. 「UML仕様書」
    著者:オブジェクト・マネージメント・グループ