クラス図の読み方
クラス図は、システムの構造をクラス(データと処理のまとまり)の関係として表した図です。オブジェクト指向の設計で使われます。
クラス図とは
役割
- クラスの構造(属性とメソッド)を表現
- クラス間の関係(継承、関連など)を表現
- システムの全体構造を俯瞰
いつ使うか
| 設計理解時 | システム構造の把握 |
| 新機能実装時 | どのクラスに実装するか判断 |
| コードリーディング時 | クラス間の関係を確認 |
| リファクタリング時 | 影響範囲の確認 |
クラス図の基本要素
クラスの表記
┌─────────────────────┐
│ User │ ← クラス名
├─────────────────────┤
│ - id: int │ ← 属性(フィールド)
│ - name: string │
│ - email: string │
├─────────────────────┤
│ + register() │ ← メソッド
│ + login() │
│ - validate() │
└─────────────────────┘
可視性(アクセス修飾子)
| 記号 | 意味 | 説明 |
|---|---|---|
| + | public | どこからでもアクセス可能 |
| - | private | クラス内部からのみアクセス可能 |
| # | protected | 継承したクラスからアクセス可能 |
| ~ | package | 同じパッケージからアクセス可能 |
クラス間の関係とその読み方
クラスには6種類の関係があり、記法・意味が異なります。自分が読みたい関係のタブを開いてください。
クラス間に「つながり」がある関係です。
classDiagram
User --> Order : 注文する
class User {
+id: int
+name: string
}
class Order {
+id: int
+total: int
}
読み方:「UserはOrderと関連がある(注文する)」
何が起きているか:ユーザーが注文を行うという「つながり」を示します。どちらが生存期間に影響するわけではありません。
「持っている」関係。部分は独立して存在できます。
classDiagram
Team o-- Member : 所属
class Team {
+name: string
}
class Member {
+name: string
}
読み方:「TeamはMemberを持つ(Memberはチームがなくても存在できる)」
何が起きているか:メンバーはチームに所属していますが、チームが削除されてもメンバーは存在します。集約を示す◇の矢印に注目します。
「構成する」関係。部分は全体がないと存在できません。
classDiagram
Order *-- OrderItem : 含む
class Order {
+id: int
}
class OrderItem {
+productId: int
+quantity: int
}
読み方:「OrderはOrderItemで構成される(OrderがなければOrderItemも存在しない)」
何が起きているか:注文明細は注文があってこそ意味があります。注文が削除されると、その注文明細も自動的に削除されるべきです。コンポジションを示す◆の矢印に注目します。
「〜の一種である」関係。あるクラスが別のクラスを拡張します。
classDiagram
Animal <|-- Dog
Animal <|-- Cat
class Animal {
+name: string
+eat()
}
class Dog {
+bark()
}
class Cat {
+meow()
}
読み方:「DogはAnimalの一種である(Animalを継承している)」
何が起きているか:DogとCatはAnimalのすべての属性・メソッドを持ち、さらに自分固有のメソッドを追加しています。継承を示す△の矢印が子クラスから親クラスへ向きます。
インターフェースの実装関係。あるクラスがインターフェースの仕様を実装します。
classDiagram
PaymentService <|.. CreditCardPayment
PaymentService <|.. BankTransfer
class PaymentService {
<<interface>>
+pay()
}
class CreditCardPayment {
+pay()
}
class BankTransfer {
+pay()
}
読み方:「CreditCardPaymentはPaymentServiceインターフェースを実装している」
何が起きているか:複数の支払い方法(クレジットカード、銀行振込)が同じPaymentServiceインターフェースを実装することで、どの支払い方法でも同じ方法で呼び出せます。実装を示す破線の矢印に注目します。
一時的な「使う」関係。関連よりも一時的で弱い結びつきです。
classDiagram
OrderService ..> EmailService : 使用
class OrderService {
+createOrder()
}
class EmailService {
+send()
}
読み方:「OrderServiceはEmailServiceを使う(依存している)」
何が起きているか:注文作成の際に、一時的にEmailServiceを使って通知メールを送ります。この関係は関連よりも一時的で、生存期間に影響しません。依存を示す破線の矢印に注目します。
関係の記号まとめ
| 関係 | 線の種類 | 矢印 | 意味 |
|---|---|---|---|
| 関連 | 実線 | → | つながりがある |
| 集約 | 実線 | ◇→ | 持っている(独立可) |
| コンポジション | 実線 | ◆→ | 構成している(一体) |
| 継承 | 実線 | △→ | 〜の一種である |
| 実装 | 破線 | △→ | インターフェースを実装 |
| 依存 | 破線 | → | 一時的に使う |
多重度(Multiplicity)
関係の「数」を表します。
| 表記 | 意味 |
|---|---|
| 1 | ちょうど1つ |
| 0..1 | 0または1つ |
| * | 0以上(複数可) |
| 1..* | 1以上(複数可) |
| 0..* | 0以上(複数可)(*と同じ) |
例
classDiagram
User "1" --> "*" Order : 注文する
Order "1" --> "1..*" OrderItem : 含む
読み方:
- 「1人のUserは0個以上のOrderを持つ」
- 「1つのOrderは1個以上のOrderItemを含む」
【サンプル】クラス図の実例
ECサイトの注文システムを例に、クラス図を読んでみましょう。
classDiagram
User "1" --> "*" Order
Order "1" *-- "1..*" OrderItem
OrderItem "*" --> "1" Product
Order --> PaymentService
class User {
-id: int
-name: string
-email: string
+register()
+login()
}
class Order {
-id: int
-userId: int
-totalAmount: int
-status: string
+create()
+cancel()
+calculateTotal()
}
class OrderItem {
-id: int
-orderId: int
-productId: int
-quantity: int
-price: int
}
class Product {
-id: int
-name: string
-price: int
-stock: int
+checkStock()
}
class PaymentService {
<<interface>>
+pay()
+refund()
}
読み解き方
- User → Order:ユーザーは複数の注文を持つ(1対多)
- Order ◆ OrderItem:注文は注文明細で構成される(コンポジション)
- OrderItem → Product:注文明細は商品を参照する
- Order → PaymentService:注文は決済サービスを使う(依存)
実装時に確認すること
| 確認項目 | このクラス図から分かること |
|---|---|
| どのクラスを作るか | User, Order, OrderItem, Product, PaymentService |
| クラスの責務 | Orderにcreate, cancel, calculateTotalがある |
| データの関係 | OrderはOrderItemを複数持つ |
| 外部連携 | PaymentServiceインターフェースで決済処理 |
クラス図を読むときのポイント
1. まず全体を俯瞰する
- どんなクラスがあるか
- 中心となるクラスは何か
- クラスの数は多すぎないか
2. 関係の種類を確認する
- 実線か破線か
- 矢印の形は何か
- 多重度はどうなっているか
3. 自分の担当範囲を特定する
- 実装するのはどのクラスか
- 関連するクラスは何か
- 影響を受けるクラスはどこまでか
よくある疑問
継承と実装の違いは?
- 継承:具体的なクラスを拡張(class Dog extends Animal)
- 実装:インターフェースを実装(class CreditCard implements PaymentService)
集約とコンポジションの違いは?
- 集約(◇):部分が独立して存在できる(チームとメンバー)
- コンポジション(◆):部分は全体がないと存在できない(注文と注文明細)
クラス図に書いてないメソッドを追加していいか?
設計者に確認しましょう。ただし、privateなヘルパーメソッドなどは追加しても問題ないことが多いです。
関連ドキュメント
- 設計書・仕様書の読み方 - 設計書全般の読み方
- 処理フロー図の読み方 - 処理フロー図の読み方
- ER図の読み方 - データベース構造の読み方