Skip to content

Unexploited Encapsulation

Tampaknya ini smell udah familiar dengan Martin Fowler - Switch Statments... Intinya jangan pakai if-else atau switch untuk seleksi Object aja..! Selesai 😀

Smell ini terjadi karena adanya pemakaian switch ataupun if-else statement untuk melakukan validasi tipe object. Smell ini hampir sama dengan smell Switch statements.

Tidak semua switch atau if-else itu berbahaya. Perlu dipertimbangkan apakah akan terjadi violasi terhadap OCP (Open Closed Principle).

Contoh

Permasalahan

Lihat class ShapePrinter.java dan CharNeededCounter.java.

java
if(shape.equalsIgnoreCase("square")){
  ...
} else if(shape.equalsIgnoreCase("triangle")){
  ...
} else {
  ...
}
if(shape.equalsIgnoreCase("square")){
  ...
} else if(shape.equalsIgnoreCase("triangle")){
  ...
} else {
  ...
}

Kedua class tersebut akan melanggar OCP. Bayangkan bila ada tipe Shape baru yang perlu dibuat, tentu saja akan bertambah lagi if di masing-masing ShapePrinter dan CharNeededCounter.

Misal bertambah logic shape Circle. Violasi OCP terjadi di 2 class tersebut.

java
if(shape.equalsIgnoreCase("square")){
  ...
} else if(shape.equalsIgnoreCase("triangle")){
  ...
} else if(shape.equalsIgnoreCase("circle")){
  ...
} else {
  ...
}
if(shape.equalsIgnoreCase("square")){
  ...
} else if(shape.equalsIgnoreCase("triangle")){
  ...
} else if(shape.equalsIgnoreCase("circle")){
  ...
} else {
  ...
}

Di dalam contoh ini, if-else square dan triangle ada di 2 class. Pada kondisi nyata bila hal ini dibiarkan terjadi, if-else square dan triangle akan terus beranak-pinak bila ada kebutuhan logic lain.

Semakin sedikit kita menggunakan if-else di dalam code, maka akan semakin baik. Bahkan ada orang yang membuat campaign untuk ini: Anti-IF Campaign.

Penyelesaian

Untuk contoh kasus ini, kita melakukan tahapan berikut:

Opsi 1: Replace Type Code with Subclasses

Kita memiliki dua type code. square dan triangle. Oleh karena itu, kita buat class Square, Shape sebagai abstract class yang memiliki fungsi charNeeded dan print, lalu Triangle.java dan Square.java meng-extends class Shape.

Opsi 2: Replace Conditional with Polymorphism

Setelah class Square dan Triangle sudah terbentuk. Logic print dari ShapePrinter dan logic menghitung karakter dari CharNeededCounter dipindahkan ke masing-masing class.

Dengan begini, bila ada jenis baru, misalkan Circle, kita tinggal extends dari class Shape.

When to Ignore

Perlu diketahui jika pada kasus tersebut berkaitan dengan masalah validasi tipe object melalui inputan user ataupun class ini dibuatkan dengan menerapkan design pattern Factory, maka perlu diketahui bahwa smell ini dapat diabaikan namun dengan catatan pada kasus ShapeFactory berikut.

ShapeFactory

User tetap akan meng-input string melalui console. Oleh karena itu, kita perlu menyiapkan sebuah class Factory untuk membuat class Shape dari string yang diinput.

Harusnya Anda menyadari bahwa terjadi violasi OCP disini. Bila class Circle dibuat, maka if di Factory bertambah. Hal ini dimaklumi karena OCP hanya dilanggar satu kali saja di dalam Factory (tidak akan dilanggar lagi di tempat lain) dan memang terpaksa dilakukan karena input dari user adalah string. Ibaratkan Factory disini berperan sebagai anti-corruption layer.

Di beberapa bahasa pemrograman, ada cara spesifik untuk mengakali menghilangkan if-else pada class Factory, contohnya untuk Java: https://www.javacodegeeks.com/2014/10/factory-without-if-else.html.

Created by Saugi