SOLID 原則
オブジェクト指向設計の 5 つの基本原則で、保守性と拡張性の高いコードを実現する
設計原則オブジェクト指向
SOLID 原則とは
SOLID は、Robert C. Martin (Uncle Bob) が提唱したオブジェクト指向設計の 5 つの基本原則の頭文字である。保守性、拡張性、テスト容易性の高いコードを実現する。
5 つの原則
| 原則 | 名前 | 一言 |
|---|---|---|
| S | 単一責任 (SRP) | クラスの変更理由は 1 つだけ |
| O | 開放閉鎖 (OCP) | 拡張に開き、修正に閉じる |
| L | リスコフ置換 (LSP) | サブタイプは親と置換可能 |
| I | インターフェース分離 (ISP) | 使わないメソッドに依存しない |
| D | 依存性逆転 (DIP) | 具象ではなく抽象に依存 |
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: 開放閉鎖の原則
// ✅ 新しい通知方法を追加しても既存コードを変更しない
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: 依存性逆転の原則
// ❌ 具象に依存
class OrderService {
private db = new DynamoDBClient({}); // 具象クラスに直接依存
}
// ✅ 抽象に依存
class OrderService {
constructor(private repo: OrderRepository) {} // インターフェースに依存
}
SOLID の過剰適用に注意
SOLID は指針であり、全てのコードに厳密に適用する必要はない。Lambda の単純な CRUD 関数に SOLID を厳密に適用すると、過度な抽象化で複雑になる。
| ケース | SOLID の適用度 |
|---|---|
| 複雑なドメインロジック | 厳密に適用 |
| 共有ライブラリ | 厳密に適用 |
| 単純な Lambda 関数 | 緩やかに適用 |
| スクリプト | 不要 |
SOLID 原則の関連書籍も参考になる。