SOLID原則の中でも特に理解が難しいとされるのがリスコフの置換原則(LSP)です。
リスコフの置換原則とは「サブクラスは基底クラスと置換可能でなければならない」という継承を正しく使うための原則であり、ポリモーフィズムの正確な動作を保証するための設計指針です。
本記事ではリスコフの置換原則の意味・定義・違反例・正しい適用方法について詳しく解説していきます。
リスコフの置換原則とは?LSPの基本的な結論
それではまず、リスコフの置換原則の基本的な定義と概念について解説していきます。
リスコフの置換原則(LSP:Liskov Substitution Principle)とは、「基底クラス(親クラス)のオブジェクトをサブクラス(子クラス)のオブジェクトで置き換えても、プログラムの正確さが変わらないようにするべきだ」という設計原則です。
バーバラ・リスコフによって1987年に提唱されたもので、SOLID原則の「L」に相当します。
簡単に言えば、「サブクラスは基底クラスの振る舞いの契約(事前条件・事後条件・不変条件)を守らなければならない」ということです。
リスコフの置換原則の核心
| 概念 | 説明 |
|---|---|
| 事前条件 | メソッド呼び出し前に成立すべき条件(サブクラスで弱めることはできるが強めてはならない) |
| 事後条件 | メソッド呼び出し後に成立すべき条件(サブクラスで強めることはできるが弱めてはならない) |
| 不変条件 | クラスの全メソッドを通じて常に成立すべき条件(サブクラスでも維持しなければならない) |
LSPと継承の関係
LSPは継承を正しく使うためのガイドラインを提供します。
継承は「is-a関係」を表現するための言語機能ですが、単に「is-a関係がある」というだけでは不十分であり、「行動的な互換性(Behavioral Compatibility)」が保たれているかどうかが重要です。
コードが「この型の変数に何が入っているかを確認せずにメソッドを呼べる」状態を維持することがLSP準拠の設計の目標です。
LSP違反の典型例:正方形と長方形
LSP違反の最もよく知られた例が「正方形と長方形」の問題です。
数学的には「正方形は長方形の一種(is-a関係)」であるため、Squareクラス(正方形)をRectangleクラス(長方形)の子クラスとして設計したくなります。
しかし長方形では「幅を変えても高さは変わらない」という不変条件がありますが、正方形では「幅を変えると高さも同じ値に変わる」ため、正方形を長方形と置き換えると既存のコードが期待どおりに動かなくなりLSP違反となります。
LSP違反の見つけ方と修正方法
続いては、LSP違反を見つけるための方法と修正のアプローチを確認していきます。
LSP違反のサイン
コード中でLSP違反が起きているサインとして最も典型的なのが、型チェック(instanceofやtype()による型判定)の多用です。
「もしこのオブジェクトがSubClassAなら〜、SubClassBなら〜」というコードが現れた場合、それはポリモーフィズムが正しく機能しておらずLSP違反の可能性が高い状態です。
型チェックなしにサブクラスのオブジェクトを基底クラスの変数で扱えることがLSP準拠の証明となります。
LSP違反を修正するアプローチ
LSP違反を解消するアプローチとして、継承関係の見直し・インターフェースへの変更・コンポジションの活用が代表的です。
正方形と長方形の例では、両者を同じ親クラスの子クラスとするのではなく、それぞれ独立したクラスとして設計するか、「四辺形」のような共通の抽象インターフェースを定義するアプローチが推奨されます。
| LSP違反のサイン | 修正アプローチ |
|---|---|
| サブクラスで基底クラスのメソッドが空実装 | 継承ではなくコンポジションを使用する |
| 型チェックによる条件分岐が多発 | ポリモーフィズムで設計を見直す |
| サブクラスで例外をスローするメソッド | インターフェースの粒度を見直す |
| 戻り値の型が基底クラスと異なる | 共変戻り値型の正しい活用を検討 |
LSPと他のSOLID原則の関係
続いては、LSPとSOLID原則の他の4つとの関係を確認していきます。
LSPとインターフェース分離原則(ISP)の関係
LSPとISPは密接に関連しており、大きすぎるインターフェースはLSP違反を誘発しやすくなります。
実装できないメソッドを含むインターフェースを実装しようとすると、空実装や例外スローという形でLSP違反が生じやすくなります。
ISPで適切な粒度にインターフェースを分離することで、LSPを守った実装がしやすくなります。
LSPとDIP(依存性逆転原則)の組み合わせ
DIPは抽象に依存することを推奨しますが、その抽象(インターフェースや抽象クラス)の契約をLSPによって正しく定義・遵守することで、DIPによる疎結合設計が正しく機能するようになります。
まとめ
本記事では、リスコフの置換原則(LSP)の意味・定義・違反例・修正アプローチ・他のSOLID原則との関係について解説しました。
LSPとはサブクラスが基底クラスと置換可能であるべきという原則であり、事前条件・事後条件・不変条件という3つの契約を守ることがLSP準拠の設計の要件です。
型チェックの多用や空実装がLSP違反のサインであり、継承の見直し・インターフェース分離・コンポジションの活用によって適切に修正することで、ポリモーフィズムが正しく機能するクリーンなオブジェクト指向設計が実現できます。
LSPを意識した継承設計の習慣を身につけ、長期的に保守しやすいコードベースを目指していきましょう。