S.O.L.I.D Principle - Liskov Substitution Principle (LSP)
Tags: programming, architecture, kotlin, oop
Published: 2021-06-20 16:11:04

Open Closed Principle yang sudah saya tulis di artikel sebelumnya merupakan salah satu kunci dari konsep Pemrograman Berbasis Objek (_Object Oriented Programming_) dimana memungkinkan kamu untuk menulis code yang robust, dapat dimaintenance, dan reusable software components. Namun hanya mengadopsi prinsip ini saja tidak cukup untuk memastikan bahwa  kamu dapat mengubah salah satu bagian dari sistemmu tanpa merusak bagian-bagian yang lain. class dan interface yang kamu miliki juga perlu mengadopsi Liskov Substitution Principle (LSP) untuk menghindari side-effect.

Liskov Substitution Principle ini memperluas Open Closed Principle dengan memfokuskan pada behavior dari superclass dan turunannya.

## Apa itu Liskov Substitution Principle (LSP)
> 💡 If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T. ~ Barbara Liskov

Kemudian Robert C. Martin merumuskan kembali definisi dari Liskov Substitution Principle yang dikemukakan oleh Barbara Liskov

> 💡 Subtypes must be substitutable for their base types.

Prinsip ini dapat juga diartikan bahwa objek-objek dari superclass seharusnya dapat digantikan dengan objek-objek yang merupakan turunan dari superclass tanpa merusak aplikasi. Dimana mengharuskan objek-objek dari turunan superclass memiliki behavior yang sama dengan superclassnya.

## Kenapa LSP ini Penting ?
Pelanggaran LSP akan membuat code anda bau. Kita mungkin telah mengeneralisasi sebuah konsep secara premature dan membuat superclass dimana tidak diperlukan. Kebutuhan dimasa mendatang untuk konsep tersebut mungkin tidak sesuai dengan hierarki class yang kita buat.

Jika code klien tidak dapat menggantikan referensi superclass dengan objek-obej subclass secara bebas, maka akan dipaksa untuk melakukan pemeriksaan instanceof dan menangani beberapa subclass secara kusus. Jika code seperti ini tersebar di seluruh code kita maka akan sulit untuk maintenancenya.

```kotlin
open class Product {
    protected val _discount: Double
    fun getDiscount(): Double {
        return _discount
    }
}
```

```kotlin
class SpecialProduct : Product() {
    fun applyExtraDiscount() {
        _discount = _discount * 0.2
    }
}
```

```kotlin
fun main(args: Array<String>) {
    val birds = listOf<Product>(Product(), SpecialProduct())
    birds.forEach { it ->
         if (it is SpecialProduct) it.applyExtraDiscount()
         println(it.getDiscount())
    }
}
```

Setiap kali kita menambahkan atau memodifikasi subclass, kita harus menyusuri code base kita dan merubahnya di beberapa tempat, ini akan sulit dilakukan dan rawan akan kesalahan.

## Solusi LSP
Code diatas berarti objek Produk tidak dapat digantikan oleh objek SpecialProduct karena kita melakukan validasi bahwa jika produk merupakan SpecialProduk maka kita akan memanggil fungsi `applyExtraDiscount()`.

agar `SpecialProduct` dapat digunakan untuk menggantikan superclassnya maka kita akan menggunakan prinsip “Tell, don’t ask!”, dimana akan membantu kita untuk mengeliminasi type casting / type checking.

```kotlin
class SpecialProduct : Product() {

    override fun getDiscount() {
        applyExtraDiscount()
        return _discount
    }
    fun applyExtraDiscount() {
        _discount = _discount * 0.2
    }
}
```

```kotlin
fun main(args: Array<String>) {
    val birds = listOf<Product>(Product(), SpecialProduct())
    birds.forEach { it ->
         println(it.getDiscount())
    }
}
```

dengan begini kita tidak memerlukan typecasting karena kita telah mengubah method dengan cara mengoverride dan memanggil fungsi `applyExtraDiscount()` di dalamnya dengan begitu tidak diperlukan lagi untuk melakukan pengecekan bahwa untuk SpecialProduct. Serta code yang kita miliki jadi lebih robust, testable, dan maintenable karena telah mengikuti LSP.


## Akhir Kata
Liskov Substitution Principle memperluas Open Closed Principle dan membuat kita dapat menggantikan objek dari superclass dengan objek-objeck turunannya tanpa merusak program yang sudah ada. Serta membantu kita untuk membuat hierarki yang sesuai antar tipe, dimana akan menjamin program kita untuk berjalan dengan benar tanpa side-effect yang tidak diinginkan.