【SOLID原則】リスコフの置換原則 - LSP
SOLID原則とは、ソフトウェア設計の5つの原則の頭字語を取ったものです。ソフトウェアをより理解しやすく、より柔軟に、よりメンテナナンス性の高いものにするために考案されました。
- 単一責任の原則(Single Responsibility Principle)
- オープン・クローズドの原則(Open/closed principle)
- リスコフの置換原則(Liskov substitution principle)
- インターフェース分離の原則(Interface segregation principle)
- 依存性逆転の原則(Dependency inversion principle)
今回はSOLID原則のひとつ、リスコフの置換原則の原則についてです。
リスコフの置換原則
簡単に言うと、派生型(サブクラス)は、その基底型(スーパークラス)と置換可能でなければならないという原則です。
リスコフの置換原則について、書籍「アジャイルソフトウェア開発の奥義」では、このように書かれています。
原則: ここで望まれるのは、次に述べるような置換可能な性質である:S型のオブジェクトo1の各々に、対応するT型のオブジェクトo2が1つ存在し、Tを使って定義されたプログラムPに対してo2の代わりにo1を使ってもPの振る舞いが変わらない場合、SはTの派生型であると言える。[1]
この引用の例を以下のコードに例えてみます。
- S型のオブジェクトo1: Taxiクラス(サブクラス)
- T型のオブジェクトo2: Carクラス(スーパークラス)
- Tを使って定義されたプログラムP: driveメソッド
class Car {
drive = () => 6
}
class Taxi extends Car {
drive = () => '5時間'
}
const print = (arg) => {
const driveTime = arg.drive()
return `${driveTime}時間運転しました`
}
const car = new Car()
console.log(print(car)) // 6時間運転しました
const taxi = new Taxi()
console.log(print(taxi)) // 5時間時間運転しました ←日本語がおかしい
TaxiクラスはCarクラスをextendsで継承しています。継承の目的は、複数のクラスにあるメソッドやプロパティをスーパークラスに定義してコードの重複をなくすことです。
継承はis-aの関係(B is a Aは、BはAの一種である)が成立していなければいけません。今回のサンプルコードを見ると、タクシーは車の一種であるが成り立ちます。
しかし、リスコフの置換原則には違反しています。先程の引用の一部を振り返ります。
o2の代わりにo1を使ってもPの振る舞いが変わらない場合、SはTの派生型であると言える。
o2の「Carクラス」の代わりにo1の「Taxiクラス」を使っても、driveメソッドの振る舞いがからない場合と言われていますが、サンプルコードでは振る舞いが変わっています。
それでは振る舞いが同じになるように、if文を追加してみましょう。
const print = (arg) => {
const driveTime = arg.drive()
if (car.constructor.name === 'Car') {
return `${driveTime}時間運転しました`
}
if (car.constructor.name === 'Taxi') {
return `${driveTime}運転しました`
}
}
今度は、オープン・クローズドの原則にも違反してしまいました。
リスコフの置換原則(さらにオープン・クローズドの原則)を守るには、継承関係にあるクラスは振る舞いが変わらないようにします。
class Car {
drive = () => 6
}
class Taxi extends Car {
drive = () => 5
}
const print = (arg) => {
const driveTime = arg.drive()
return `${driveTime}時間運転しました`
}
const car = new Car()
console.log(print(car)) // 6時間運転しました
const taxi = new Taxi()
console.log(print(taxi)) // 5時間運転しました
今回はdriveメソッドの戻り値を揃えることで、スーパークラスとサブクラスが置換可能になりました。オープン・クローズドの原則も守ることができ、コードがシンプルになります。
-
Robert C. Martin. アジャイルソフトウェア開発の奥義 ↩︎
Discussion