Open Closed Principle ini dapat didefinisikan sebagai berikut:
💡 Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification
yang berarti setiap entitas perangkat lunak (class, module, fungsi, dsb.) sebaiknya terbuka untuk dilakukan ekstensi, dan tertutup untuk modifikasi. Kita seharusnya dapat menambahkan behavior baru tanpa perlu merubah implementasinya.
Tujuan dari prinsip ini untuk menghindari kemungkinan terjadinya bug-bug baru ketika kita merubah implementasi code yang sudah uda.
Ilustrasi Open Closed Principle:
Image Source
Seperti gambar Illustrasi di atas, Terdapat 1 Mesin Blender, dan beberapa wadah untuk blender yang digunakan untuk kasus-kasus yang berbeda, dimana ada yang untuk memblender daging, memblender buah, memblender bumbu dapur. Jadi wadah tersebut memiliki fungsi yang berbeda-beda tanpa harus merubah fungsi utama dari mesin blender.
Contoh Kasus
Kita ambil contoh Blender di atas. Misal anda memiliki class Blender yang memiliki fungsi untuk memblender buah buahan
class Blender {
fun blend() {
println("Mulai memblender")
}
}
lalu ada kebutuhan dari Produk yang membuat class Blender anda dapat daging, dan bumbu dapur / rempah-rempah.
Jika anda tidak mengikuti prinsip Open Closed Principle mungkin saja anda akan melakukan hal seperti ini:
class Blender {
fun blend(tipe: String) {
when (tipe) {
"BUAH" -> blendFruit()
"DAGING" -> blendMeat()
"REMPAH" -> blendSpices()
}
}
private fun blendFruit() {
println("Mulai memblender Buah")
}
fun blendMeat() {
println("Mulai memblender Daging")
}
fun blendSpices() {
println("Mulai memblender rempah-rempah")
}
}
Jika anda melakukan hal tersebut sangat memungkinkan terciptanya bug baru karena anda telah mengubah code yang sebelumnya telah berjalan normal.
Code Improvement
Sekarang kita akan coba melakukan improvement agar sesuai dengan prinsip OCP.
interface Processor {
fun process()
}
kita siapkan antarmuka / abstraksi yang akan kita gunakan sebagai cetakan processor-processor yang akan kita buat nanti.
Lalu kita mulai buat masing-masing processor menggunakan cetakan yang sudah ada.
class FruitProcessor() : Processor {
override fun process() {
println("Mulai memblender Buah")
}
}
class MeatProcessor() : Processor {
override fun process() {
println("Mulai memblender Daging")
}
}
class SpicesProcessor() : Processor {
override fun process() {
println("Mulai memblender rempah-rempah")
}
}
setelah kita buat masing-masing processor nya untuk memproses masing-masing bahan olahan.
kita menambahkan parameter di fungsi blend dengan object Processor yang akan kita gunakan untuk memproses bahan olahan.
class Blender {
fun blend(processor: Processor) {
processor.process()
}
}
Lantas apa yang terjadi ketika produk ingin menambahkan kebutuhan untuk memblender batu es (ice cube) ?
Kita tinggal membuat class baru yang mengimplementasikan interface Processor
class IceCubeProcessor() : Processor {
override fun process() {
println("Mulai memblender batu es")
}
}
sehingga kita tidak perlu mengubah class Blender yang sebelumnya sudah berjalan.
Manfaat
- fungsionalitas dari class 'X' dapat dengan mudah diperluas dengan fungsionalitas yang baru dengan dikemas dalam kelas yang terpisah dari class 'X' tanpa perlu mengubah implementasi di class 'X' (tidak ada perubahan di class 'X')
- code anda menjadi loosely coupled
- class 'Y' yang di pakai di dalam class 'X' dapat dengan mudah dimock (dipalsukan), sehingga membuat class 'X' lebih mudah untuk di test.
Akhir Kata
Sekian dan terimakasih, Saya harap anda bisa menerapkan prinsip ini sehingga code yang anda tulis akan mencadi lebih bersih, mudah untuk test, lebih mudah untuk dikembangkan lagi, dan dapat menunjang produktivitas anda.
Top comments (0)