単一責任の原則(SRP)の概念は理解できていても、実際の設計でどのように適用すればよいかで悩む開発者は多いでしょう。
SRPの適用は一朝一夕に身につくものではなく、「責任の特定」「クラス分割の判断」「リファクタリングの実践」という継続的な思考プロセスを通じて磨かれていきます。
本記事ではSRPの具体的な適用方法と実践的な設計手法について詳しく解説していきます。
SRP適用の基本プロセス:実践的な結論
それではまず、SRPを実際のコードに適用するための基本的なプロセスについて解説していきます。
SRP適用の基本プロセスは3つのステップで構成されます。
第1ステップが「クラスの変更理由を洗い出す」こと、第2ステップが「複数の変更理由が存在する場合は責任を分割する」こと、第3ステップが「分割後のクラス間の関係を整理して依存関係を明確にする」ことです。
SRP適用の基本フロー
| ステップ | 内容 | 判断基準 |
|---|---|---|
| 1. 変更理由の洗い出し | クラスが変更される理由をすべて列挙 | 「なぜこのクラスを変更するか」を問う |
| 2. 責任の分割判断 | 複数の変更理由があれば分割候補 | 理由が2つ以上あれば分割を検討 |
| 3. 依存関係の整理 | 分割後のクラス間の関係を設計 | 依存の方向が一方向になるよう設計 |
責任を特定するための問いかけ
SRPを適用するためのスタートは「このクラスは何の責任を持っているか?」という問いかけです。
具体的には「このクラスを変更しなければならない理由を5つ挙げられるか?」という問いに対し、3つ以上の異なる理由が思い浮かぶ場合はSRP違反の可能性が高いと判断できます。
「〜かつ〜」という形でクラスの責任を説明しなければならない場合も、複数責任のサインとして意識しておくとよいでしょう。
クラス分割の実践的な方法
責任の特定が完了したら、次は適切なクラス分割の実施です。
既存クラスから責任を切り出す際は、まず切り出す機能に対応するインターフェースまたは新クラスを定義し、元のクラスから新クラスへ処理を移動します。
この際、元のクラスから新クラスに対して依存する形(元クラスが新クラスを呼び出す)にするか、DI(依存性注入)で疎結合にするかを検討します。
テストが存在する場合はリファクタリング前に確認し、分割後も既存テストが通ることを確認しながら進めることが安全な移行の基本です。
設計パターンとSRPの組み合わせ
続いては、SRPと相性のよい設計パターンと組み合わせ方を確認していきます。
ファサードパターンによる複雑さの管理
SRPによってクラスを細かく分割すると、クライアントが多くのクラスを直接操作する必要が生じることがあります。
このような場合にファサードパターンが有効で、複数の細粒度クラスをまとめる窓口クラス(ファサード)を提供することで、クライアントの複雑さを隠蔽しながらSRPによる分割の恩恵も享受できます。
ストラテジパターンとSRPの相性
アルゴリズムや処理ロジックを切り替える必要がある場合、ストラテジパターンとSRPの組み合わせが効果的です。
各アルゴリズムを独立したストラテジクラスとして実装することで、それぞれのクラスが一つのアルゴリズムという単一責任を持つ設計が自然に実現します。
関数型プログラミングとSRPの類似性
関数型プログラミングの思想もSRPと非常に近い考え方を持っています。
純粋関数(同じ入力に対して常に同じ出力を返し副作用がない関数)は本質的に単一責任を持っており、関数型スタイルを取り入れることでSRPを自然に実践できる場合があります。
既存コードへのSRP適用(リファクタリング)
続いては、既存のコードにSRPを適用してリファクタリングを行う際の実践的な手順を確認していきます。
段階的リファクタリングのアプローチ
SRP違反のコードをリファクタリングする際は、一度にすべてを変更しようとせず段階的に進めることが重要です。
まずテストを追加して既存の振る舞いを保護し、次に最も影響範囲の小さい責任から切り出し、最後に依存関係を整理するという順序で進めることが推奨されます。
「ボーイスカウトの原則(コードを見つけたときより少し良い状態にして返す)」の考え方で、毎回の変更時に少しずつSRPを改善していく積み重ねが現実的です。
| リファクタリング手順 | 内容 |
|---|---|
| 1. テスト追加 | 既存の振る舞いを保護するテストを記述 |
| 2. 責任の特定 | 変更理由を洗い出して分割対象を決定 |
| 3. 新クラス作成 | 切り出す責任の新クラスを定義 |
| 4. 移行・委譲 | 処理を新クラスに移動・既存クラスから委譲 |
| 5. テスト確認 | 既存テストが通ることを確認 |
まとめ
本記事では、単一責任の原則の具体的な適用方法・責任の特定プロセス・設計パターンとの組み合わせ・リファクタリングの手順について解説しました。
SRPの適用は「変更理由を問う」「責任を分割する」「依存関係を整理する」という3つのステップで実践でき、ファサード・ストラテジパターンとの組み合わせによってより洗練された設計が実現します。
段階的なリファクタリングと日々の積み重ねを通じて、SRPを設計思考の自然な一部として身につけることが、長期的に高品質なソフトウェアを開発し続けるための最も確実な道筋です。
コードレビューや設計議論でSRPを意識的に活用し、チームの設計力を継続的に向上させていきましょう。