design-patterns について
開発者が定番のデザインパターンを選び、適用するためのリファレンススキルです。問題や症状ごとにパターンを整理し、テンプレートの機械的な適用ではなく、状況に合った利用を重視します。
主な機能
- 01問題・症状別のパターン選択
- 02設計の基本原則
- 03一般的な分類ごとのパターン参照
- 04アンチパターンと誤用の指針
- 05実装チェックリスト
活用シーン
- 01繰り返し起きる設計課題にパターンを選ぶ
- 02コードの症状から適用候補を探す
- 03過剰な設計のリスクを確認する
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ ratacat/ claude-skills --skill design-patternsインストール後、Claude Code で/design-patternsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
patterns/adapter.mdbuilder.mdchain-of-responsibility.mdcommand.mdcomposite.mddecorator.mddto.mdfacade.mdfactory.mdidentity-map.mdlazy-load.mdmediator.mdobserver.mdproxy.mdrepository.mdservice-layer.mdstate.mdstrategy.mdtemplate-method.mdunit-of-work.md詳細
デザインパターン
概要
デザインパターンは、繰り返し発生するソフトウェア設計上の問題に対する、実証済みの解決策です。設計について議論するための共通語彙を提供し、何十年にもわたる実践を通じて磨かれてきた知見を集約しています。
基本理念: パターンは、状況に合わせて応用するためのテンプレートであり、そのままコピーする設計図ではありません。設計を本当にシンプルにできる場合に適切なパターンを使いましょう。感心させたり、必要以上に複雑にしたりするために使うものではありません。
基礎となる原則
次の原則は、優れた設計すべてを支えています。
| 原則 | 意味 | 違反したときの兆候 |
|---|---|---|
| 変化するものをカプセル化する | 変化する部分を安定した部分から分離する | 変更の影響がコードベース全体に波及する |
| インターフェースに対してプログラミングする | 具象ではなく抽象に依存する | 実装を入れ替えられない |
| 継承よりコンポジションを優先する | オブジェクトを組み合わせて振る舞いを構築する | 深くて柔軟性のないクラス階層になる |
| 疎結合にする | オブジェクト間の相互依存を最小限にする | あるものを変更すると別のものが壊れてしまう |
| オープン・クローズドの原則 | 拡張に対して開き、変更に対して閉じる | 新機能の追加に既存コードの編集が必要になる |
| 単一責任の原則 | クラスを変更する理由を1つにする | クラスが多くのことをしすぎている |
| 依存性逆転の原則 | 上位モジュールが下位モジュールに依存しない | ビジネスロジックがインフラストラクチャと密結合している |
パターンの選び方
問題の種類から選ぶ
CREATING OBJECTS
├── Complex/conditional creation ──────────→ Factory Method
├── Families of related objects ───────────→ Abstract Factory
├── Step-by-step construction ─────────────→ Builder
├── Clone existing objects ────────────────→ Prototype
└── Single instance needed ────────────────→ Singleton (use sparingly!)
STRUCTURING/COMPOSING OBJECTS
├── Incompatible interface ────────────────→ Adapter
├── Simplify complex subsystem ────────────→ Facade
├── Tree/hierarchy structure ──────────────→ Composite
├── Add behavior dynamically ──────────────→ Decorator
└── Control access to object ──────────────→ Proxy
MANAGING COMMUNICATION/BEHAVIOR
├── One-to-many notification ──────────────→ Observer
├── Encapsulate requests as objects ───────→ Command
├── Behavior varies by internal state ─────→ State
├── Swap algorithms at runtime ────────────→ Strategy
├── Algorithm skeleton with hooks ─────────→ Template Method
├── Reduce N-to-N communication ───────────→ Mediator
└── Sequential handlers ───────────────────→ Chain of Responsibility
MANAGING DATA ACCESS
├── Abstract data source ──────────────────→ Repository
├── Track changes for atomic commit ───────→ Unit of Work
├── Ensure object identity ────────────────→ Identity Map
├── Defer expensive loading ───────────────→ Lazy Load
├── Map objects to database ───────────────→ Data Mapper
└── Shape data for transfer ───────────────→ DTO
症状から選ぶ
| 症状 | 検討するパターン |
|---|---|
| 型に対する巨大な switch/if-else 文がある | Strategy、State、またはポリモーフィズム |
| クラス間でコードが重複している | Template Method、Strategy |
| 多数のオブジェクトに変更を通知する必要がある | Observer |
| オブジェクトの生成ロジックが複雑である | Factory、Builder |
| 機能の追加でクラスが肥大化する | Decorator |
| サードパーティ製 API がコードに適合しない | Adapter |
| コンポーネント間の依存関係が多すぎる | Mediator、Facade |
| データベースやネットワークなしではテストできない | Repository、Dependency Injection |
| 元に戻す/やり直す必要がある | Command |
| オブジェクトの振る舞いが状態に依存する | State |
| リクエストを複数のハンドラーで処理する必要がある | Chain of Responsibility |
ドメインロジック:トランザクションスクリプトとドメインモデル
| 要素 | トランザクションスクリプト | ドメインモデル |
|---|---|---|
| ロジックの複雑さ | シンプル(500行未満) | 複雑で、ルールが多い |
| ビジネスルール | 少なく、単純 | 多く、互いに作用する |
| 操作 | CRUD が中心 | 豊かな振る舞い |
| チーム/期間 | 小規模チーム、短期間でのリリース | 長期的な保守 |
| テスト | 結合テスト | ドメインの単体テスト |
経験則: まずはトランザクションスクリプトから始めます。手続き型コードの保守が難しくなったら、ドメインモデルにリファクタリングします。
クイックリファレンス
Tier 1:必須パターン(最初に習得)
| パターン | 一言で言うと | 使用する場面 | リファレンス |
|---|---|---|---|
| Strategy | 交換可能なアルゴリズムをカプセル化する | 何かを実現する方法が複数あり、実行時に切り替える場合 | strategy.md |
| Observer | 依存するオブジェクトに状態の変更を通知する | イベントシステム、リアクティブな更新 | observer.md |
| Factory | オブジェクトの生成をカプセル化する | 生成が複雑、または条件に依存する場合 | factory.md |
| Decorator | 振る舞いを動的に追加する | 継承せずに拡張する場合 | decorator.md |
| Command | リクエストをオブジェクトとしてカプセル化する | 元に戻す/やり直す、キューイング、ロギング | command.md |
Tier 2:構造パターン
| パターン | 一言で言うと | 使用する場面 | 参考資料 |
|---|---|---|---|
| Adapter | インターフェースを変換する | 互換性のないコードを統合する | adapter.md |
| Facade | 複雑なサブシステムを単純化する | シンプルな API の背後に複雑さを隠す | facade.md |
| Composite | 均一なツリー構造を実現する | 全体と部分の階層構造を扱う | composite.md |
| Proxy | オブジェクトへのアクセスを制御する | 遅延読み込み、アクセス制御、キャッシュ | proxy.md |
Tier 3:エンタープライズ/アーキテクチャパターン
| パターン | 一言で言うと | 使用する場面 | 参考資料 |
|---|---|---|---|
| Repository | コレクションのようなデータアクセスを提供する | ドメイン層とデータ層を分離する | repository.md |
| Unit of Work | 原子的な変更を調整する | トランザクション管理 | unit-of-work.md |
| Service Layer | ビジネス処理を統括する | アプリケーションの境界を定義する | service-layer.md |
| DTO | 転送用にデータを整形する | API コントラクト、過剰な情報公開の防止 | dto.md |
その他の重要なパターン
| パターン | 一言で言うと | 使用する場面 | 参考資料 |
|---|---|---|---|
| Builder | オブジェクトを段階的に構築する | 複雑なオブジェクト、流れるような API | builder.md |
| State | 状態に応じて振る舞いを変える | ステートマシン、ワークフロー | state.md |
| Template Method | フックを備えたアルゴリズムの骨格 | フレームワークの拡張ポイント | template-method.md |
| Chain of Responsibility | ハンドラーにリクエストを順に渡す | ミドルウェア、パイプライン | chain-of-responsibility.md |
| Mediator | 複雑な通信を一元化する | コンポーネント間の結合を減らす | mediator.md |
| Lazy Load | コストの高い読み込みを遅らせる | パフォーマンス、大規模なオブジェクトグラフ | lazy-load.md |
| Identity Map | オブジェクトの同一性を保証する | ORM、重複の防止 | identity-map.md |
よくある間違い
| 間違い | 症状 | 対処法 |
|---|---|---|
| パターンの使いすぎ | 単純な操作にも多くのクラスをたどる必要がある | 実際の問題を解決する場合にのみ使う |
| 不適切なパターン | コードに無理があり、不自然に感じられる | 実際の問題を見直す |
| 継承の乱用 | 深い階層、壊れやすい基底クラス | 継承よりコンポジションを優先する(Strategy、Decorator) |
| Singleton の乱用 | グローバル状態、隠れた依存関係、テストの難しさ | 代わりに依存性注入を使う |
| 時期尚早な抽象化 | 実装が1つしかないインターフェース | 実際に変更の必要が生じるまで待つ |
注意すべきアンチパターン
- God Object: 1つのクラスがすべてを担う → SRP に従って分割する
- Anemic Domain Model: オブジェクトが単なるデータの入れ物になっている → 振る舞いをオブジェクトに移す
- Golden Hammer: どこでも同じパターンを使う → 問題に合ったパターンを選ぶ
- Lava Flow: 誰も削除しないデッドコード → 削除する。VCS が変更を記録してくれる
現代的なバリエーション
| 現代的なパターン | 基になるパターン | 説明 |
|---|---|---|
| Dependency Injection | Strategy + Factory | コンテナーが依存関係を作成し、注入する |
| Middleware | Decorator + Chain of Responsibility | リクエスト/レスポンスのパイプライン |
| Event Sourcing | Command | 状態の変更をイベントとして保存する |
| CQRS | Command/Query の分離 | 読み取りモデルと書き込みモデルを分離する |
| Hooks (React/Vue) | Observer + Strategy | 関数型のライフサイクル購読 |
実装チェックリスト
パターンを実装する前に確認してください。
- このパターンは、このコードベースの実際の問題を解決する
- よりシンプルな代替案を検討した
- この状況においてトレードオフを許容できる
- チームがこのパターンを理解している
- 解決策を過剰に設計しない
コメント
Markdown 対応