SOLID Principles

Posted by

Ini merupakan article pertama saya. Artikel pertama ini saya akan membahas mengenai SOLID Principles.  Prinsip-prinsip solid ini akan membantu para programmer atau software developer dalam membangun suatu sistem yang lebih mudah dibaca(readable), mudah ditest (testable), mudah untuk di-mantain (mantainable)

Apa itu SOLID?

Single Responsibility Principle

Open Closed Principle

Liskov Substitution Principle

Interface Segregation Principle

Depedency Inversion Principle

Mari kita kupas satu per satu

  1. Single Responsibility Principle

    THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.

    Apa artinya? Satu class / method mempunyai hanya tepat satu tanggung jawab (responsibility). Jika class / method tersebut memiliki dua tanggung jawab, maka lakukan refactoring dengan membuat satu class / method baru. Sebagai contoh :

    import java.util.Date;
    public interface Service {
       public void saveInventory(Inventory inventory);
       public void updateInventory(Inventory inventory);
       public void deleteInventory(Inventory inventory);
       public Double checkIncome(Date date);
       public Double checkOutcome(Date date);
    }

    Dari contoh diatas kita melihat bahwa class Service memiliki 2 responsibility yaitu menangani inventory dan juga pemasukan & pengeluaran. Hal ini tentu melanggar single responsibility principle. Sehingga class diatas bisa kita pecah menjadi 2 class yaitu InventoryService dan FinanceService.

    public interface InventoryService {
      public void saveInventory(Inventory inventory);
      public void updateInventory(Inventory inventory);
      public void deleteInventory(Inventory inventory);
    }
    
    public interface FinanceService {
      public Double checkIncome(Date date);
      public Double checkOutcome(Date date);
    }

    Dengan memecah class Service menjadi InventoryService dan FinanceService maka setiap class tersebut akan bertanggung jawab terhadap perubahan-perubahan didalam class tersebut. Dalam artian, InventoryService hanya akan bertanggung jawab apabila ada perubahan task di dalam class InventoryService. Demikian juga dengan FinanceServic

  2. Open Closed Principle

    SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION BUT CLOSED FOR MODIFICATION.

    Class harus open for extension namun close for modification. Open for extension artinya desain  class sehingga ketika menambahkan fungsi baru harus dapat ditambahkan. Close for modification artinya sebuah class yang telah didevelop, harusnya tidak dimodifikasi lagi kecuali karena bug. Namun kemungkinan adanya penambahan fitur, perubahan requirement bisa saja terjadi. Mau tidak mau harus menambahkan fungsi untuk mengimplementasikan requirement tersebut. Penambahan fitur atau perubahan requirement bisa dilakukan dengan membuat suatu class baru yang mengimplementasikan sebuah interface ataupun abstract. Disinila prinsip Open Close Principle dibutuhkan dengan membatasi perubahan pada class yang telah didevelop sebelumnya sehingga tidak menimbulkan bug baru terhadap code yang telah ada.
    Open Closed Principle dapat dilakukan dengan menggunakan interface ataupun abstract class.

    Mari kita lihat contoh berikut:

    public class Animal {
      private String name;
      public void getNameAnimal() {
        if ("elephant".equals(name)) {
          System.out.println("Name of animal is elephant");
        } else if("tiger".equals(name)) {
          System.out.println("Name of animal is tiger");
        } else if("cat".equals(name)) {
          System.out.println("Name of animal is cat");
        } else {
          System.out.println("This is animal");
        }
      }
    }

    Pada contoh diatas bisa kita lihat bahwa class Animal tersebut melanggar Open Closed Principle. Mari kita test dengan hal berikut:

    • Setiap kali user mau menambahkan jenis Animal baru, apakah bisa mengextend behaviour dari class tersebut tanpa memodifikasinya?
      Tidak. Berarti class tersebut bukan Open for extension
    • Setiap kali user mau menambahkan jenis Animal baru, apakah kita harus memodifikasi class Animal ?
      Ya. Berarti class tersebut bukan Closed for modification

    Dari hal tersebut, class diatas perlu kita refactor, menjadi :

    public abstract class Animal {
      public void getNameAnimal();
    }
    public class Elephant extends Animal{
      @Override
      public void getNameAnimal() {
        System.out.println("Name of animal is elephant");
      }
    }
    public class Tiger extends Animal{
      public void getNameAnimal() {
        System.out.println("Name of animal is Tiger");
      }
    }
    

    Dari hasil refactor diatas, mari kita test apakah masih melanggar open closed principle dengan hal berikut:

    • Setiap kali user mau menambahkan jenis Animal baru, apakah bisa mengextend behaviour dari class tersebut tanpa memodifikasinya?
      Bisa, karena kita bisa menambahkan class jenis animal baru dan mengextend class animal. Berarti class tersebut Open for extension
    • Setiap kali user mau menambahkan jenis Animal baru, apakah kita harus memodifikasi class Animal ?
      Tidak. Berarti class tersebut Closed for modification
  3. Liskov Substitution Principle

    FUNCTIONS THAT USE … REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT.

    Prinsip ini menjelaskan bahwa superclass harus dapat digantikan dengan objek dari subclass tanpa berefek terhadap aplikasi. Hal ini dilakukan dengan object dari subclass memiliki perilaku yang sama dengan superclass. Dimana parameter dan return value sama dengan superclass.

    public class Tambah {
      public int operasi(int a, int b) {
        return a + b;
      }
    }
    
    public class Kurang {
      public int operasi(int a, int b) {
        return a - b;
      }
    }

    Dari contoh diatas method operasi bisa menjadi bagian dari superclass. selama superclass bisa menjamin melakukan operasi. Input parameter dan return value dari method operasi sama.

    Implementasi sebagai berikut:

    public interface Kalkulator {
      public int operasi(int a, int b);
    }
    
    public class Kurang implements Kalkulator{
      @Override
      public int operasi(int a, int b) {
        return a - b;
      }
    }
    
    public class Tambah implements Kalkulator{
      @Override
      public int operasi(int a, int b) {
        return a + b;
      }
    }
    
  4. Interface Segregation Principle

    CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE

    Pada Interface Segregation principle, class yang ingin menggunakan interface / abstract class bisa tidak mengimplementasikan method tidak digunakan class tersebut.

    public interface Animal {
      public void makan();
      public void menyusui();
    }
    
    public class Ayam implements Animal{
      @Override
      public void makan() {
        System.out.println("ayam makan");
      }
      @Override
      public void menyusui() {
        throw new IllegalStateException("not implement yet");
      }
    }
    public class Sapi implements Animal{
      @Override
      public void menyusui() {
        System.out.println("Sapi menyusui");
      }
      @Override
      public void makan() {
        System.out.println("sapi makan");
      }
    }

    Dari contoh diatas bisa kita liat bahwa class Ayam tidak perlu mengimplementasikan method menyusui. Sedangkan class Sapi mengimplementasikan method menyusui dan makan. Hal ini melanggar Interface Segregation Principle, sehingga perlu kita pecah interface tersebut kedalam interface yang dibutuhkan class tersebut. Contoh diatas bisa direfactor sebagai berikut:

    public interface Animal {
      public void makan();
    }
    public interface Mamalia {
      public void menyusui();
    }

    Dari hasil refactoring diatas, interface dibagi menjadi 2 bagian yaitu Animal dan Mamalia. Sehingga class yang hanya membutuhkan method menyusui bisa mengimplementasi interface yang dibutuhkannya saja.

  5. Depedency Inversion Principle

    1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
    2. Abstractions should not depend on details. Details should depend on abstractions.

    Depedency Inversion Principle bertujuan untuk melepas keterikatan antara high level dan low level class. High level dan low level class bergantung pada abstraction. High level merupakan class yang mengimplementasikan solusi bisnis secara keseluruhan. Low level merupakan class yang berisi operasi yang lebih detail seperti operasi ke database, dll.

    public class Karyawan {
      Gaji gaji = new Gaji();
      public double hitungBonusTahunan() {
        ...
        return gaji.hitungBonusTahunan(1, 4000000);
      }
    }
    public class Gaji {
      public double hitungBonusTahunan(int tahun, double gaji) {
        double bonusTahunan = tahun * gaji * 2;
        return bonusTahunan;
      }
    }

    Contoh diatas tidak mengikuti aturan Depedency Inversion Principle. Karena class Karyawan(High level class) bergantung pada class Gaji(low level class). Dalam skenario yang lebih kompleks perubahan pada class Gaji bisa mengubah class Karyawan dan itu menyalahi aturan DIP. Sehingga untuk mengikuti prinsip DIP, kita harus menghapus depedency secara langsung antar class. Hal ini bisa dilakukan dengan menerapkan abstraction seperti interface atau abstract class.

    public interface Gaji {
      public double hitungBonusTahunan(int tahun, double gaji);
    }
    public class GajiImpl implements Gaji{
      @Override
      public double hitungBonusTahunan(int tahun, double gaji) {
        double bonusTahunan = tahun * gaji * 2;
        return bonusTahunan;
      }
    }
    public class Karyawan {
      private Gaji gaji;
      public Karyawan(Gaji gaji) {
        this.gaji = gaji;
      }
      public double hitungBonusTahunan() {
        ...
        return gaji.hitungBonusTahunan(1, 4000000);
      }	
    }

    Contoh diatas sudah menerapkan DIP. Bisa kita lihat bahwa class Karyawan tidak dependent secara langsung ke low level class yaitu GajiImpl tapi melalui interface yaitu class gaji.

Penutup

Demikian bahasan kali ini mengenai SOLID Principle.
Semoga bermanfaat dan selamat menerapkan.
Penulis terbuka menerima saran dan kritik untuk kebaikan artikel ini.

References

https://stackify.com/solid-design-liskov-substitution-principle/
http://www.blackwasp.co.uk/SOLIDPrinciples.aspx
Pablo’s SOLID Software Development

Share to
  • 4
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
    4
    Shares
  • 4
    Shares

Leave a Reply

Your email address will not be published. Required fields are marked *