SOLID 原則
オブジェクト指向設計の 5 つの基本原則で、保守性と拡張性の高いコードを実現する
設計原則オブジェクト指向
SOLID 原則とは
SOLID は、Robert C. Martin (Uncle Bob) が提唱したオブジェクト指向設計の 5 つの基本原則の頭文字である。保守性、拡張性、テスト容易性の高いコードを実現する。
5 つの原則
5 つの原則を以下にまとめる。
| 原則 | 名前 | 一言 |
|---|---|---|
| S | 単一責任 (SRP) | クラスの変更理由は 1 つだけ |
| O | 開放閉鎖 (OCP) | 拡張に開き、修正に閉じる |
| L | リスコフ置換 (LSP) | サブタイプは親と置換可能 |
| I | インターフェース分離 (ISP) | 使わないメソッドに依存しない |
| D | 依存性逆転 (DIP) | 具象ではなく抽象に依存 |
S: 単一責任の原則
S: 単一責任の原則のコード例を示す。
// ❌ 1 つのクラスに複数の責務
class UserService {
createUser(data: UserInput) { /* DB 操作 */ }
sendWelcomeEmail(user: User) { /* メール送信 */ }
generateReport(users: User[]) { /* レポート生成 */ }
}
// ✅ 責務ごとに分離
class UserRepository { create(data: UserInput) { /* DB 操作 */ } }
class EmailService { sendWelcome(user: User) { /* メール送信 */ } }
class ReportGenerator { generate(users: User[]) { /* レポート生成 */ } }
O: 開放閉鎖の原則
O: 開放閉鎖の原則のコード例を示す。
// ✅ 新しい通知方法を追加しても既存コードを変更しない
interface Notifier { notify(message: string): Promise<void>; }
class EmailNotifier implements Notifier { async notify(msg: string) { /* メール */ } }
class SlackNotifier implements Notifier { async notify(msg: string) { /* Slack */ } }
// 新しい通知方法を追加: 既存コードの変更なし
class SmsNotifier implements Notifier { async notify(msg: string) { /* SMS */ } }
D: 依存性逆転の原則
D: 依存性逆転の原則のコード例を示す。
// ❌ 具象に依存
class OrderService {
private db = new DynamoDBClient({}); // 具象クラスに直接依存
}
// ✅ 抽象に依存
class OrderService {
constructor(private repo: OrderRepository) {} // インターフェースに依存
}
SOLID の過剰適用に注意
SOLID は指針であり、全てのコードに厳密に適用する必要はない。Lambda の単純な CRUD 関数に SOLID を厳密に適用すると、過度な抽象化で複雑になる。
| ケース | SOLID の適用度 |
|---|---|
| 複雑なドメインロジック | 厳密に適用 |
| 共有ライブラリ | 厳密に適用 |
| 単純な Lambda 関数 | 緩やかに適用 |
| スクリプト | 不要 |
SOLID 原則の関連書籍も参考になる。
この記事は役に立ちましたか?
関連用語
リスコフの置換原則
SOLID の L - サブタイプはスーパータイプと置換可能でなければならない原則
インターフェース分離の原則
SOLID の I - クライアントが使わないメソッドへの依存を強制しない原則
依存性逆転の原則
SOLID の D - 上位モジュールは下位モジュールに依存せず、両者とも抽象に依存すべきという設計原則
DRY 原則
Don't Repeat Yourself の略で、知識の重複を排除し、単一の正を維持する設計原則
Twelve-Factor App
クラウドネイティブなアプリケーションを構築するための 12 の設計原則
単一責任の原則
SOLID の S - クラスやモジュールが変更される理由は 1 つだけであるべきという設計原則