SOLIDTypeScript設計原則
SOLID原則をTypeScriptで15分で理解する
SOLID原則は、オブジェクト指向設計の5つの基本原則です。
- S — Single Responsibility Principle(単一責任の原則)
- O — Open/Closed Principle(開放閉鎖原則)
- L — Liskov Substitution Principle(リスコフの置換原則)
- I — Interface Segregation Principle(インターフェース分離の原則)
- D — Dependency Inversion Principle(依存性逆転の原則)
名前だけ覚えても意味がありません。なぜ重要なのかを、TypeScriptコードで見ていきましょう。
S: Single Responsibility
クラスは1つの理由でしか変更されてはいけない。
// ❌ 2つの理由で変わる
class User {
constructor(public name: string, public email: string) {}
save() { /* DBに保存 */ }
sendEmail() { /* メール送信 */ }
}
// ✅ 1つの責任
class User {
constructor(public name: string, public email: string) {}
}
class UserRepository { save(user: User) { /* ... */ } }
class UserMailer { send(user: User) { /* ... */ } }
O: Open/Closed
拡張に対して開いて、修正に対して閉じている。
// ❌ 支払い方法を追加するたびに修正が必要
class PaymentProcessor {
pay(method: string, amount: number) {
if (method === "credit") { /* ... */ }
else if (method === "paypal") { /* ... */ }
// 新方式を追加するたびにここを変更
}
}
// ✅ 新しい支払い方法はクラスを追加するだけ
interface PaymentMethod {
pay(amount: number): void;
}
class CreditCardPayment implements PaymentMethod { /* ... */ }
class PaypalPayment implements PaymentMethod { /* ... */ }
L: Liskov Substitution
派生クラスは基底クラスの代わりに使えなければならない。
派生クラスが基底クラスより「制約」を増やしてはいけない。例えば、Rectangleを継承したSquareで幅と高さを同時に変更すると、Rectangle前提のコードが壊れます。
I: Interface Segregation
使わないメソッドへの依存を強制するな。
1つの巨大なインターフェースより、小さく特化した複数のインターフェースの方が良い。
D: Dependency Inversion
高レベルモジュールは低レベルモジュールに依存するな。両方とも抽象に依存せよ。
// ❌ UserServiceがMySQLに直接依存
class UserService {
private db = new MySQL();
}
// ✅ 抽象に依存
class UserService {
constructor(private db: Database) {}
}
テストでMockを注入できる、DB変更に強い、などの恩恵があります。
CodeSenseiで体感する
SOLID原則は「読んで理解する」より「自分のコードで体感する」ほうが100倍身につきます。
CodeSenseiにあなたのクラスを見せてみてください。「このコードからSOLIDのどの原則が体感できるか」をAIが教えてくれます。