โ† Kembali ke Konsep OOP
๐Ÿ”„
Prinsip

Liskov Substitution

Subtype harus bisa menggantikan base type-nya tanpa mengubah kebenaran program.

Masalahnya

Jika subclass meng-override perilaku dengan cara yang melanggar ekspektasi base class-nya, misalnya melempar error untuk operasi yang didukung base class atau mengembalikan hasil yang tak terduga, kode yang mengandalkan base type akan rusak saat diberi subtype tersebut.

Cara Kerja

  • โ€บSubclass harus menghormati kontrak (precondition, postcondition, invariant) dari superclass-nya
  • โ€บMethod yang di-override harus menerima input setidaknya seluas method dasarnya dan mengembalikan output yang tidak lebih longgar
  • โ€บContoh pelanggaran klasik: Square extends Rectangle tetapi merusak independensi setWidth/setHeight
  • โ€บJika subtype tidak bisa sepenuhnya memenuhi kontrak base type, pertimbangkan ulang relasi inheritance-nya

Kapan Digunakan

โœ“Merancang hierarki class di mana subclass harus bisa langsung menggantikan induknya
โœ“Meninjau inheritance untuk mencari perilaku override yang mengejutkan
โœ“Memilih antara inheritance dan composition untuk relasi yang "hampir is-a"

Contoh di Dunia Nyata

๐ŸŽ
iOS

Subclass UIView mana pun harus bekerja dengan benar di mana pun UIView diharapkan

๐Ÿค–
Android

Subclass RecyclerView.ViewHolder mana pun harus berperilaku benar di dalam adapter

๐ŸŒ
Web

Implementasi Storage mana pun (localStorage/sessionStorage) harus mendukung kontrak get/set/remove yang sama

Contoh Kode

Swift
// โŒ Violation: Penguin can't fly, breaking the Bird contract
// class Penguin: Bird { override func fly() { fatalError("can't fly") } }

// โœ… Fix: separate flying ability into its own protocol
protocol Bird {
    func eat()
}

protocol FlyingBird: Bird {
    func fly()
}

struct Sparrow: FlyingBird {
    func eat() { print("Sparrow eating") }
    func fly() { print("Sparrow flying") }
}

struct Penguin: Bird {
    func eat() { print("Penguin eating") }
    // no fly() โ€” Penguin is not a FlyingBird, and that's fine
}

func feed(_ bird: Bird) { bird.eat() }
feed(Penguin())   // works correctly for any Bird