今回はSOLID原則のL、リスコフの置換原則についてまとめていきます。SRPとOCPに比べて説明しずらいというか、記事にしにくかったです…
SOLID原則
- S:単一責任の原則(SRP:Single Responsibility Principle)
- O:オープン・クローズドの原則(OCP:Open-Closed Principle)
- L:リスコフの置換原則(LSP:Liskov Substitution Principle)
- I:インターフェース分離の原則(ISP:Interface Segregation Principle)
- D:依存関係逆転の原則(DIP:Dependency Inversion Principle)
リスコフの置換原則とは
S が T の派生型であれば、プログラム内で T 型のオブジェクトが使われている箇所は全て S 型のオブジェクトで置換可能であれ
SOLID原則のの中でも初見で一番何を言われているのかわからない原則だと思います。そのまま説明していくこともできますが、まずは別の表現を確認してみましょう。
派生型は基本型と置換可能でなければならない
だいぶシンプルになりましたが、今度は派生型とか基本型とかキーワードの意味がわかりませんね。次項から図解しながらリスコフの置換原則が述べるポイントについて解説していきます。
基本型と派生型
ある果物屋さんを例にして解説していきます。
そのお店のお客さんは、果物の「値段」「生産者」を必ず確認してから購入します(例えば、「値段」が期待する値段より安いか、「生産者」が自分が知っている信頼できる人かどうかを確認して両方の条件に当てはまったら購入するなど)。
そんなお客さんのために、お店の果物には「値段」と「生産者」の情報が付いています。この果物が「値段」と「生産者」の情報を持っている状態を基本型とします。そしてお店にはリンゴとオレンジとブドウがあり、すべて果物の派生型です。
(ブドウだけ生産者のところが空白ですが今はスルーしましょう)
原則に反しない例
果物(基本型)の派生型であるリンゴとオレンジには「値段」「生産者」の情報がしっかり表示されています。すると、お客さんは「値段」と「生産者」の両方の情報を見て買うか考えるという、期待していた通りの処理を進めることができます。
原則に反する例
ブドウだけ生産者の情報が無かったとします。お客さんは値段しかわからないため、値段だけを見て購入するかどうか考えるという、リンゴやオレンジとは異なる例外的な処理を求められます。
派生型は基本型と置換可能とは?
原則の文章“派生型は基本型と置換可能でなければならない”の置換可能とは、果物(基本型)の位置に派生型であるリンゴ、オレンジ、ブドウを直接配置してもお客さんが処理できる状態のことを指しています。
お客さんは購入時に値段と生産者の両方の情報を見て購入するか考えたいので「果物であれば値段と生産者の情報がついている」ということを期待しています。
リンゴやオレンジなら値段・生産者の情報を持っているため、置換可能な派生型ということになります。しかし、ブドウは生産者の情報を欠いているため、基本型と置換可能な派生型ではないわけです。
たとえ話を原則に寄せて整理する
今回の例では、お客さん=果物という関数・クラスを呼び出す処理に該当します。
お客さんは常に果物に「値段」「生産者」を期待した呼び出し方をしますが、ブドウの時だけ「生産者」がないこと前提に以降の処理(購入判断)をしなければならず、特別な処理を追加する必要あります。コードレベルの話をすれば、きっとブドウの時専用のif文を入れたりすることでしょう。
呼び出し側の処理も変更しないと実装できないような処理の追加はやめようね、という原則とも言い換えることができます。
まとめ
リスコフの置換原則に反して派生型が基本型と置換可能でなかった場合、その派生型を処理する場合だけは呼び出し元で特殊な処理をしなければなりません。処理を無駄に複雑化させるコードになりかねませんし、呼び出し元の処理に修正を加えなければ機能を拡張できないという意味では、オープンクローズドの原則にも反しています。
今回は上記1例にて説明しましたが、リスコフの置換原則は他のNGパターン(基本型よりも派生型の方が持っている情報が多い場合など)もあります。そういった説明は、すでに私なんかよりも詳しい方々が説明してくれていますので、そういった記事を読まれる際も、この内容が解釈の助けになれば幸いです。
参考
Clean Architecture(著:Robert C.Martin,2018)
コメント