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.
open class Product {
protected val _discount: Double
fun getDiscount(): Double {
return _discount
}
}
class SpecialProduct : Product() {
fun applyExtraDiscount() {
_discount = _discount * 0.2
}
}
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.
class SpecialProduct : Product() {
override fun getDiscount() {
applyExtraDiscount()
return _discount
}
fun applyExtraDiscount() {
_discount = _discount * 0.2
}
}
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.
Top comments (0)