- クラス図はシステムの静的構造(クラスとその関係)を可視化する図
- クラスは「名前」「属性」「操作」で表す
- 可視性は
+ - # ~の記号で表す - 関係は 関連・集約・合成・継承・実現・依存 を線や矢印で表す
クラス図とは
クラス図は UML(Unified Modeling Language) における最も基本的かつ重要な図の1つで、ソフトウェアやシステムの構造を可視化するために使われます。
- 目的:システム内の「クラス」とそれらの「関係」を表現すること。以下のような役割を持ちます。
- ソフトウェアの静的な構造を把握
- 設計や仕様の共有
- 実装への橋渡し
- 特徴
- 主にオブジェクト指向開発で使用する
- 「何が存在するか(構造)」を示すもので、「どのように動くか(動作)」は別の図(※)が担当
- 設計初期では概念レベルのモデリング、後期では詳細な実装仕様の設計に使える
※動作を示す図:シーケンス図、アクティビティ図など。
クラス図の表記
クラス図は大きく分けて、「クラス」、「可視性(アクセス修飾子)」、「関係」の三つで表記していく図です。
クラス図における各要素の表記方法について以下にまとめます。
クラスの表記
クラスは長方形で表され、通常は「名前」「属性」「操作」の3区画に分けて記述します。
各区画の基本的な記法は以下の通りになります。
- クラス名
- 先頭大文字の単数形が基本(例:User, Order)
- 先頭大文字の単数形が基本(例:User, Order)
- 属性(フィールド)
- 書き方:
可視性 名前 : 型 = 初期値 - 例:
- id : int = 0
- 書き方:
- 操作(メソッド)
- 書き方:
可視性 名前(引数 : 型) : 戻り値の型 - 例:
+ login(username : String, password : String) : boolean
- 書き方:
可視性(アクセス修飾子)の表記
可視性は、クラスの属性や操作(メソッド)がどこから参照・利用できるかを示すものです。
記号で表現され、主に次の4種類があります。
| 記号 | 可視性 | 意味 |
|---|---|---|
+ | public(公開) | どこからでもアクセスできる |
- | private(非公開) | 同一クラス内からのみアクセス可能 |
# | protected(保護) | 同一クラスおよびサブクラスからアクセス可能 |
~ | package(デフォルト/パッケージ) | 同一パッケージ内からアクセス可能 |
関係の表記
関係は、クラス同士のつながりを矢印や線で表すもので、以下のような種類があります。
| 関係名 | 意味 | 使用例 |
|---|---|---|
関連(Association)![]() | クラス同士が何らかの関係を持つ (参照/非参照の関係が不定) | プレイヤー ― 所持アイテム |
双方向関連![]() | 双方が互いを参照 | キャラクター ↔ 装備 |
単方向関連![]() | 一方向だけが参照 | UI → ゲームマネージャ |
誘導可能性![]() | 一方向だけが参照かつ、逆方向からの参照不可を明示 | プレイヤー ×→ インベントリ |
| 多重度(Multiplicity) | 関係数を表す | パーティ 1..* ― 0..1 プレイヤー |
集約(Aggregation)![]() | 弱い「所有」関係(部分は全体無しでも存在) | メンバー ―◇ チーム |
コンポジション(Composition)![]() | 強い「所有」関係(部分は全体に従属) | ステータス ―◆ キャラクター |
継承(Generalization)![]() | サブクラスがスーパークラスを継承 (汎化関係とも言います) | 敵 ー▷ キャラクター |
実装(Interface Realization)![]() | クラスがインターフェースを実装 | プレイヤー入力制御 —▷ IInputHandler |
依存(Dependency)![]() | 一時的に利用する(引数・ローカル変数など) | 敵AI —> ナビゲーション |
| 関連クラス (Association Class) ![]() | 関係自体に属性を持たせる (要素間の関連に属性や操作を追加) | キャラ ―<関連クラス:「装備スロット」ー 装備 |
クラス図の作成手順
いかに簡単なクラス図を作成する際の手順をまとめます。
仕様書から作成
0. 前提
- ユースケース・要件書・画面仕様などを用意する
1. 名詞を見つる
- 要件や仕様の文章で名詞(Person, 注文, 商品 等)を見つけ、「クラス候補」としてリストアップする。
- 同じ意味の別名は統一する(例:顧客 = User)。
2. クラス候補を性質で振り分ける
- 「単に値を持つだけで振る舞いを持たない」→ 属性として記述
(例:注文日のorderDate : Date、郵便番号postalCode : String) - 「振る舞い(処理)を持つなら」→ クラスとして定義し、
操作(メソッド)を列挙
(例:Order.calculateTotal(): Money、User.login(id, pw): boolean) - 「不変で同値性が値で決まる」→
<<value object>>としてクラス化(属性だけでよい)
(例:Money、Address)
3. クラス間の関係整理
- 「複数クラスに共通の属性や振る舞いがある」→共通のスーパークラス or インタフェースを作る(
継承or実現)
(判断基準:is-a が明確なら継承、振る舞いだけ共有させたいならインタフェース。) - 「クラス間に、A が B を包含する(ホスト/部品)関係がある」→(集約/合成)
- 部品は独立して存在可能 → 集約(白ひし形)。
- 部品は全体にライフサイクルが縛られる(全体が消えると部品も消える) → 合成(黒ひし形)。
例:House ◆— Room(合成)、Team ◇— Player(集約)
- 「クラス間が、B は A の特殊化(例:Dog is-a Animal)で表現できる」→ 継承(汎化)
※注意点:継承は振る舞い/契約の共有に適するが、多用は避ける(コンポジション優先を検討)。 - 「メソッドの引数やローカルで一時的に参照するだけ」→ 依存 (フィールドとして保持しないことを意味)
- 実装上どちらのクラスが相手を参照する必要があるか明確
→関連線に矢印をつけて navigability を表す。不要な双方向参照は避ける。(誘導可能性の記述)
4. 多重度の記述
- 関係の「個数の制約」がわかるなら → 各端に
1/0..1/*/1..*を書く。
実装対応例:*→ List/Set 等、0..1→ Optional / nullable。 - A と B が多対多で関係する → 中間エンティティ(結合クラス)を作る。
(例:学生と科目 → 結合クラス:履修)
5. クラス図の整理
- ロール名・役割名の記述
- 同じクラス同士の関連や、端の意味を明確にしたいとき
→ 関連端にroleName : Typeを付ける(例:orderItems : OrderItem [*])。
- 同じクラス同士の関連や、端の意味を明確にしたいとき
- 集約よりコンポジション(合成)を優先すべきか検討
- ライフサイクルが強く結びつく(部品は単独で意味がない)なら
→ 記述:合成(黒ひし形)。特にドメインモデルでは合成が明示的で有益。
- ライフサイクルが強く結びつく(部品は単独で意味がない)なら
- ユーティリティ/サービスクラスの扱い
- 状態を持たず、単に処理を提供する(例:価格計算ロジック)なら
→ クラス図に含めるか省略かを検討。含めるなら<<service>>や<<utility>>を付ける
- 状態を持たず、単に処理を提供する(例:価格計算ロジック)なら
- 永続化/DB マッピングを考慮
- クラスが永続化される(エンティティ)なら
→<<entity>>を付け、ID 属性(例:- id : Long)と永続化に必要なキーを明示する。
- クラスが永続化される(エンティティ)なら
- 抽象クラス / インタフェースの扱い
- 共通振る舞いを定義し、実装を分離したい場合
→ 抽象メソッドを斜体 or<<abstract>>、インタフェースは<<interface>>で表す。
実装は破線の実現(実線三角)。
- 共通振る舞いを定義し、実装を分離したい場合
- 肥大化への対処
- クラスが属性7個以上またはメソッドが多く責務が複数派生している
→ 責務ごとに分割(SRP 遵守)、値オブジェクト化、サブクラス化または委譲(composition)へ。
- クラスが属性7個以上またはメソッドが多く責務が複数派生している
- 実装用の注記
- 実装言語が決まっている(Java, Python 等)
→マッピング注記を図の横に書く(例:1..* -> List<OrderItem>、0..1 -> Optional<T>)。
- 実装言語が決まっている(Java, Python 等)
コードからクラス図を作成
1. クラス宣言を見つけたら
- 条件:
classやinterface、enumを見つけたら - 記述:クラス図の「クラス」として追加する。
- 注記:
interface→<<interface>>を付けるabstract class→<<abstract>>とするenum→<<enum>>として扱う
2. フィールド(メンバ変数)を見つけたら
- 条件:クラス内部のフィールドを見つけたら
- 記述:クラスの「属性」として追加する。
- 表記ルール:
- 可視性記号をコードに対応させる
public→+private→-protected→#- (Java のデフォルト / package-private)→
~ - 型を記載する(例:
- id : int) - 初期値がある場合は記述可能(例:
= 0)
3. メソッドを見つけたら
- 条件:クラス内部のメソッド定義を見つけたら
- 記述:クラスの「操作」として追加する。
- 表記ルール:
- 可視性(
+ - # ~)を付ける - 引数の型と戻り値の型を記述
- 例:
+ login(username : String, password : String) : boolean abstractメソッドなら斜体表記 or<<abstract>>staticメソッドは下線で表記
- 可視性(
4. 継承/実装を見つけたら
- 条件:
extends/implementsを見つけたら - 記述:
extends→ 継承(汎化:実線+空白三角矢印)implements→ 実現(破線+空白三角矢印)
5. フィールドの型が別クラスなら
- 条件:フィールドの型が他のクラス型になっている場合(例:
Orderクラス内にUser user;) - 記述:クラス間に 関連(実線) を追加。
- 追記:
- コレクション型(
List<OrderItem>など) → 多重度* Optional<T>や nullable → 多重度0..1- それ以外 → 多重度
1
- コレクション型(
6. メソッドの引数や戻り値が別クラスなら
- 条件:メソッドのシグネチャに他クラスが登場する場合
- 記述:依存(破線矢印) を追加。
- 例:
void register(Order order)→このクラス → Orderに依存。
7. 内部クラス/ネストクラスがあるなら
- 条件:クラスの内部に
static classやinner classがある場合 - 記述:クラス図で 入れ子 にするか、関連として示す。
8. 合成/集約の判定(コードから推測)
- 合成(黒ひし形):
- 条件:フィールドがコンストラクタで必ず生成され、ライフサイクルが一致する場合
- 集約(白ひし形):
- 条件:フィールドが外部から渡され、独立して存在可能
9. 誘導可能性(ナビゲーション)を決める
- 条件:
- フィールドに相手クラスを持っている → 「保持側 → 相手クラス」に矢印を付ける
- 相手クラスにその逆がなければ片方向の関連になる
10. 不要なクラスを省く
- 条件:テスト用、DTO 専用、ユーティリティなど「ドメインの本質に関係ない」クラスを含んでいる場合
- 実行:クラス図の対象範囲に含めるかどうかを整理する。
- 備考:必要なら
<<utility>><<service>><<test>>などを付ける。
11. パッケージ/モジュールを考慮する
- 条件:コードに
package/ 名前空間がある場合 - 記述:クラス図をパッケージごとにまとめる。
12. 調整
- 条件:全クラス・関係を抽出し終えたら
- 調整:
- 多重度を補完(
1/0..1/*) - 抽象クラスやインタフェースに注記を付ける
- 複雑な関係はサブ図やパッケージ図に分割する
- 多重度を補完(











