definiton of liskov substitution is like that
🤔 The Liskov Substitution Principle (LSP) states that subtypes must be substitutable for their base types
But simply put, it would be just
😀 🎉🎉🎉🎉 follow the rules of parent class !🎉🎉🎉🎉
I'm gonna show you sample code, but don't forget this simple definition that I created
👎 Bad code
You want to drink water, and make MountainWater and RiverWater, then drink them
interface IWater {
shower: () => void
drink: () => void
wash: () => void
}
class Water implements IWater{
drink() {
console.log('drink it !!')
}
shower() {
console.log('take a shower!!')
}
wash() {
console.log('wash somewhere with it !!')
}
}
class MountainWater extends Water {
drink() {
console.log('drink it !! you even feel like were are in mountain !!')
}
}
class RiverWater extends Water {
// 🔥🔥🔥shouldn't change parent class rule !!🔥🔥🔥
drink() {
throw new Error('Do not drink it !! this is dirty !!!!! dangerous !!!!')
}
shower() {
console.log('you could take a shower with it, but be careful')
}
}
const makeWaterDrink = (water: IWater) => {
water.drink()
}
const waterInEverest = new MountainWater()
const waterFromTap = new RiverWater()
makeWaterDrink(waterInEverest)
makeWaterDrink(waterFromTap)
// drink it !! it is pure
// throw new Error('Do not drink it !! this is dirty !!!!! dangerous !!!!')
Problem in this code is that drink() function
should be void
, but you throw error
.
Yeah you don't follow rules of parent class !!
👍 Good code
// ⭐⭐ Divide interfaces
interface IPureWater {
shower: () => void
drink: () => void
}
interface IDirtyWater {
shower: () => void
wash: () => void
}
class PureWater implements IPureWater {
shower() {
console.log('you can take a shower with it normally !!')
}
drink() {
console.log('drink it !!')
}
}
class DirtyWater implements IDirtyWater {
shower() {
console.log('you could take a shower, but be careful')
}
wash() {
console.log('you can wash somewhere')
}
// ⭐⭐ You don't need to write about drink() ⭐⭐
// because you divided interfaces
}
class MountainWater extends PureWater{
drink() {
console.log('drink it !!! you even feel like you were in mountain !!')
}
}
class RiverWater extends DirtyWater{}
const makeWaterDrink = (water: IPureWater) => {
water.drink()
}
const makeWashWater = (water: IDirtyWater) => {
water.wash()
}
const waterInEverest = new MountainWater()
const waterFromTap = new RiverWater()
makeWaterDrink(waterInEverest)
makeWashWater(waterFromTap)
// drink it !!! you even feel like you are in mountain !!
// you can wash somewhere
Thanks for dividing interface from just Iwater
to IPureWater
and IDirtyWater
, all classes follow parent class rule now !!
This is simple liskov substitution sample
😀 follow the rules of parent class !
(Someone wouldn't agree with that, because it's too simple, but for beginners it's enough, I think)
ref
https://youtu.be/dJQMqNOC4Pc?t=324
https://www.membersedge.co.jp/blog/typescript-solid-liskov-substitution-principle/
Top comments (0)