UML とは何か(まず全体像)
UML は「図でプログラムを表すための共通ルール」のようなものです。
Java のコードを、箱や矢印で表現して「このシステムにはどんなモノがいて、どうつながっているか」を見える化するために使います。
ポイントは「書き方を完璧に覚えること」ではなく
「図を見たときに、だいたい何が言いたいか読めるようになること」です。
ここでは、現場でよく出てくるクラス図とシーケンス図を中心に、読み方に絞って説明します。
クラス図の読み方(箱と線が何を意味するか)
クラスの箱を読む
クラス図では、ひとつのクラスは「3 段の箱」で描かれます。
一番上の段にクラス名が書かれます。
真ん中の段にフィールド(属性)が書かれます。
一番下の段にメソッド(操作)が書かれます。
例えば、次の Java クラスがあるとします。
public class User {
private String id;
private String name;
public String id() { return id; }
public String name() { return name; }
}
Javaクラス図上では頭の中でこう読みます。
クラス名の段に「User」
属性の段に「id : String」「name : String」
操作の段に「id() : String」「name() : String」
記号もよく出てきます。
属性やメソッドの前に「+」「-」「#」が付いていたら、可視性を表しています。
「+」は public(どこからでも呼べる)
「-」は private(そのクラスの中だけで使う)
「#」は protected(サブクラスなどから使う)
と対応させて読むと、Java とのつながりが見えてきます。
クラス同士を結ぶ線(関連)を読む
箱と箱の間の線は「関連」です。
意味はシンプルで、「このクラスは、あのクラスを知っている(参照している)」です。
例えば、次のコード。
public class Address {
private String city;
}
public class User {
private String name;
private Address address; // User は Address をフィールドに持っている
}
Javaクラス図では User と Address の箱が線で結ばれます。
この線を見たときは「User は Address をフィールドに持っているんだな」と読めればOKです。
さらに線の端に数字や記号が書いてあれば「多重度」です。
User 側に「1」、Address 側に「1」と書かれていれば「ユーザ 1 人に対して住所 1 つ」。
User 側に「1」、Address 側に「0..1」と書いてあれば「住所はあってもなくてもいい」。
Post と Comment の線で、Comment 側に「*」と書かれていれば「記事 1 つにコメントが複数」という意味です。
「数字=片側から見たときに相手が何件あるか」と覚えておくと読みやすくなります。
三角形の矢印(継承・実装)を読む
クラス間を結ぶ、先が白い三角形の矢印は「継承(一般化)」です。
矢印の先が親クラス、根本側が子クラスです。
public abstract class Animal {
public abstract void speak();
}
public class Dog extends Animal {
@Override
public void speak() { System.out.println("wan"); }
}
Javaこの関係はクラス図では「Dog から Animal へ白い三角矢印」で描かれます。
図を見たときは「Dog は Animal の一種(is-a)」と読みます。
インターフェースの implements も、よく似た形で描かれます。
実装クラスからインターフェースへ、三角形付きの点線矢印が伸びていたら
「このクラスはこのインターフェースを実装している」と読めば大丈夫です。
典型的なクラス図を Java 目線で読む練習
例 1: ユーザと住所
クラス図のイメージを文章で表現するとこうです。
「User」というクラスの箱があり、属性に「id : String」「name : String」「address : Address」が書いてある。
「Address」というクラスの箱があり、属性に「city : String」「street : String」が書いてある。
User と Address の箱の間に線があり、User 側に「1」、Address 側に「0..1」と書いてある。
これを Java に翻訳する感覚で読むと、
User は id と name を持っていて、Address 型のフィールド address を持っている。
Address は city と street を持っている。
User から見た Address は「0 または 1 件」なので、住所がないユーザもありえる。
と理解できます。
コードにすると、こんなイメージです。
public class Address {
private String city;
private String street;
}
public class User {
private String id;
private String name;
private Address address; // 0..1 多重度:null 許容などで表現
}
Java図を見て「フィールドの型」「多重度」「必須か任意か」を読み取る練習をすると、一気に理解が進みます。
例 2: 記事、コメント、フォーマッタ
文章でクラス図のイメージを表すと、
クラス「Post」があり、属性に「title : String」があり、
「comments : List<Comment>」「formatter : Formatter」を持っている。
クラス「Comment」があり、「message : String」を持っている。
インターフェース「Formatter」があり、「format(raw : String) : String」というメソッドがある。
クラス「UpperFormatter」から「Formatter」に三角形付き矢印が伸びている。
Post と Comment が線で結ばれ、Post 側に「1」、Comment 側に「*」が書かれている。
これを Java 目線で読むと、
Post は複数の Comment を持っている(1 対 多)。
Post は Formatter 型のフィールドを持っている。
UpperFormatter は Formatter を実装している。
と理解できます。
コードにすると次のような感じです。
public interface Formatter {
String format(String raw);
}
public class UpperFormatter implements Formatter {
@Override
public String format(String raw) {
return raw == null ? "" : raw.toUpperCase();
}
}
public class Comment {
private String message;
}
public class Post {
private String title;
private List<Comment> comments;
private Formatter formatter;
}
Javaクラス図の「箱と線と矢印」を見るたびに「Java に直したらどうなる?」と頭で変換するクセを付けると、図が一気に読みやすくなります。
シーケンス図の読み方(メソッド呼び出しの流れを見る)
縦の線と横の矢印を読む
シーケンス図は「時間の流れに沿って、オブジェクト同士のメソッド呼び出しがどう行われるか」を表します。
上から下へ時間が流れ、左から右にオブジェクトが並びます。
縦の点線(ライフライン)は「あるオブジェクトの時間軸」を表します。
横の矢印は「メソッド呼び出し」です。
例えば、こんな処理を考えます。
class Controller {
private final UserService service;
Controller(UserService service) { this.service = service; }
void handle() {
service.createUser("Taro");
}
}
class UserService {
private final UserRepository repo;
UserService(UserRepository repo) { this.repo = repo; }
void createUser(String name) {
repo.save(new User(name));
}
}
interface UserRepository {
void save(User user);
}
Javaシーケンス図では、左から「Controller」「UserService」「UserRepository」が縦に並んで、
Controller から UserService へ「createUser()」の矢印、
UserService から UserRepository へ「save()」の矢印が順番に描かれます。
図を読むときは、上から順に目で追いながら
最初に Controller の handle() が呼ばれる
Controller が service.createUser(“Taro”) を呼ぶ
UserService が repo.save(new User(“Taro”)) を呼ぶ
と、「どのオブジェクトが、どの順番で、誰に何を頼んでいるか」を追っていけば十分です。
戻り値の矢印を読む
細かく描かれる図では、メソッドの戻り値も点線の矢印で描かれます。
「呼んだ側へ戻る矢印」があったら、「ここで戻り値が返ってきているんだな」と読むくらいで大丈夫です。
初心者のうちは、戻り値の内容よりも「呼び出しの順番」と「誰が誰に依頼しているか」を読むことに集中してください。
それだけでも、コードを読む前にロジックの大枠をつかめるようになります。
強調したい重要ポイント(UML を“使える”形で読む)
一番大事なのは「UML を暗記すること」ではなく、「図を見て Java の設計意図を読み取れること」です。
クラス図では、
箱の上段はクラス名、中段はフィールド、下段はメソッド。
「+」「-」「#」は public / private / protected。
箱と箱の線は「フィールドで参照している」関係。
線の端の数字は「多重度」(1 件か、0..1 か、* か)。
白三角矢印は継承・実装(is-a)。
シーケンス図では、
上から下が時間の流れ。
縦線がオブジェクトのライフライン。
横の矢印がメソッド呼び出し。
矢印のラベルがメソッド名。
このくらいが読めれば、現場の UML にだいぶついていけるはずです。
