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)