クラス設計書の位置づけ

クラス設計書はシーケンス図・API設計書と連携して「どのクラスがどのメソッドを持ち何を担うか」を定義する。実装前にこれをレビューすることで設計上の問題を早期に発見できる。

💡 単一責任の原則(SRP)

各クラスは「1つの責任」だけを持つように設計する。クラスの責務を1文で表現できない場合は分割を検討する。

定義すべき項目一覧

分類定義項目必須度
モジュールパッケージ/モジュール構成・階層
クラス基本クラス名・スーパークラス・実装インターフェース
クラス基本クラスの責務(1文で表現)
属性属性名・型・可視性・説明
メソッドメソッド名・引数・戻り値・可視性・処理概要
依存関係依存するクラス・関係種別(集約/合成/使用)
設計パターン適用するデザインパターン

モジュール構成図

モジュール構成例(Eコマースシステム)
com.example
├── api/                    コントローラー層
│   ├── OrderController
│   └── UserController
├── service/                ビジネスロジック層
│   ├── OrderService
│   └── StockService
├── repository/             データアクセス層
│   └── OrderRepository
├── domain/                 ドメインモデル
│   ├── Order
│   └── Product
└── exception/              カスタム例外
    └── BusinessException

依存方向の原則:
api -> service -> repository -> domain

クラス定義

クラス名責務スーパークラス実装IF
OrderService注文の確定・キャンセル・履歴照会のビジネスロジックを担うIOrderService
StockService在庫の照会・引当・補充のビジネスロジックを担うIStockService
OrderRepositoryorders テーブルのCRUD操作を担うBaseRepositoryIOrderRepository

メソッド定義

メソッド定義例(OrderService)
class OrderService:

  + confirmOrder(request: OrderRequest): OrderResponse
      引数: OrderRequest(userId, items)
      戻値: OrderResponse(orderId, totalAmount)
      処理: 1.在庫確認 2.注文レコード作成 3.在庫引当 4.通知送信
      例外: BizException(BIZ_001) 在庫不足時

  + cancelOrder(orderId: long, userId: long): void
      処理: 1.注文存在確認 2.権限確認 3.ステータス確認 4.引当解除
      例外: ResourceNotFoundException / BizException(BIZ_002)

依存関係定義

クラス依存先関係説明
OrderControllerOrderService使用(DI)コントローラーがサービスを呼び出す
OrderServiceOrderRepository使用(DI)サービスがリポジトリを通じてDB操作
OrderServiceStockService使用(DI)注文時に在庫確認・引当を委譲
OrderOrderItem合成Orderは1以上のOrderItemを保有

設計パターンの適用

パターン適用箇所目的
Repository パターン*Repository クラスデータアクセス実装をビジネスロジックから分離
Dependency Injection全サービスクラステスタビリティ向上・疎結合の実現
Factory パターンOrderFactory注文オブジェクトの生成ロジックを集約

Python Tips — import 依存関係の自動解析

Python — モジュール依存関係の自動抽出(AST)
import ast
from pathlib import Path
from collections import defaultdict

def extract_imports(filepath):
    try:
        source = Path(filepath).read_text(encoding="utf-8")
        tree = ast.parse(source)
    except Exception:
        return []
    imports = []
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            for alias in node.names:
                imports.append(alias.name.split(".")[0])
        elif isinstance(node, ast.ImportFrom):
            if node.module:
                imports.append(node.module.split(".")[0])
    return imports

def analyze_project(project_dir):
    deps = defaultdict(set)
    py_files = list(Path(project_dir).rglob("*.py"))
    project_modules = {f.stem for f in py_files}
    for py_file in py_files:
        module_name = py_file.stem
        for imp in extract_imports(str(py_file)):
            if imp in project_modules and imp != module_name:
                deps[module_name].add(imp)
    return dict(deps)

# 実行例
deps = analyze_project(".")
print("# モジュール依存関係")
for module, depends_on in sorted(deps.items()):
    if depends_on:
        print(f"  {module:30s} -> {', '.join(sorted(depends_on))}")

レビューチェックリスト

#チェック項目
1各クラスの責務が1文で表現できるか(単一責任)
2循環依存が発生していないか
3依存の方向が上位層→下位層に統一されているか
4全メソッドに引数・戻り値・処理概要が定義されているか
5テストしやすい設計(DI・インターフェース活用)か