リスコフの置換原則 (LSP)
Liskov Substitution Principle, LSP
基底型(親)から派生型(子)に置換可能であるときにのみ、継承関係を与えるべき、というもの
「Interfaceの正しい使い方」で直感的にイメージするものの話をしている

継承関係のあるものに応用できる
Interfaceの利用
ざっくりいうと
①ある箇所で、 親
を利用している時に、
②その 親
を、 子
に変えても全く正常に機能する場合にのみ、
③ 親
と 子
は(この順序)で親子関係にできる
「 親
を 子
に置換可能であるべき」という原則
この図は、最初から
親
子
と命名しているので、若干語弊があるが、言いたいことはわかるはず

classでなくInterfaceでも同じ
Licence
というInterfaceと、それを実装している2つの ~~Licence
classがある
Billing
classはそれらの利用者
Interfaceを用いている場合は、そもそも①のような書き方をしているので
②の置換が可能になる
図の矢印は依存の向きなので、置換の向きではないことに注意

この意味で、継承もInterfaceも「リスコフの置換原則を満たしているもの」として同じものと捉えることができる
継承の解説時に「継承はInterfaceだ」のように言われるのは、恐らくこの原則のことを暗に前提している
以下の2つの実装者に対しての注意喚起と言える
継承を作ろうとしている人
今から継承関係のあるclassを作ろうとしている人
今から定義しようとしている、その子classは、親から置換可能ですか?
親のinterfaceのどれを使っても、子は正しく機能しますか?
抽象が存在するものを利用しようとしている人
上の図の 利用者
目線
今から使用しようとしているモノは、具象ではなく抽象に依存していますか?
要はこういうように書け、というもの
tsconst pl: Licence = new PersonalLicence(); // o
const pl: PersonalLicence = new PersonalLicence(); // x
PersonalLicence
を使う時に、 PersonalLicence
の具体的な中身を意識して使うのではなく、 Licence
のInterfaceを意識して使えよ、という感じ
継承関係として定義すべきでないものの例
defaultのOOP言語機能として提供される「継承」の作るための制約が弱すぎる
だから何でもかんでも継承にすることができるし、
実際それは原則を守っていないので、ゆくゆく破滅するということが生じる
言語機能が貧弱だし、人間も貧弱なので、契約プログラミングしてどうにかしよう、になる
リスコフの置換原則を無視して継承を作った時にどういう問題が生じるのか
なぜそもそもそういう原則が存在するのか?
関連