Berpisah lebih baik, prinsip SOLID





Atas kuasa Allah SWT, setiap orang memiliki batas kemampuannya masing-masing. dan kita sering membanggakan seseorang atau diri sendiri dari berapa banyak beban atau tanggung jawab yang mampu dipikul, semakin banyak kemampuannya maka semakin kita membanggakannya. Begitu juga ketika kita menciptakan software, kita akan senang ketika berhasil membuat software yang memiliki banyak fitur. Akan tetapi, berbeda ketika kita membuat sebuah Class.

Class, adalah komponen yang sering kali kita remehkan penggunaannya, dengan begitu kita membuat satu class memiliki banyak beragam fungsi, sehingga classnya menjadi gemuk, semakin gemuk suatu class maka semakin sulit untuk mempelajarinya, serta semakin sulit jika suatu waktu ingin membersihkan skrip-skrip yang sudah tidak terpakai.

Maka gunakanlah prinsip SOLID, yaitu singkatan dari

1.Single Responsibility Principle
2.Open/Closed Principle
3.Liskov Substitution Principle
4.Interface Segregation Principle
5.Dependency Inversion Principle

1. Single Responsibility Principle

Artinya, suatu kelas seharusnya hanya mempunyai satu tujuan, Contohnya adalah class User di bawah ini

class User{
public function getName() {}
public function getEmail() {}
public function find($id) {}
public function save() {}
}

Class diatas memiliki dua tujuan, yaitu memanajemen eksistensi data (getter setter) variabel dan menyimpan dan mengambil data (entah melalui API, session, file atau database). Maka akan lebih baik kalau class di atas, dipisah menjadi dua class, contohnya di bawah ini

class User{
public function getName() {}
public function getEmail() {}
}

class UserRepository{
public function find($id) {}
public function save(User $user) {}
}

Sekarang ada dua class, satu untuk memanajemen variabel di dalam class User, satu lagi untuk memanajemen dari mana dan ke mana class User ini disimpan, dua class untuk dua tujuan.


2. Open/Closed Principle

Yaitu class yang kita buat(misal class hitung), bisa digunakan di kemudian hari oleh class lain tanpa harus merubah skrip yang ada di class hitung. Disebut open dalam artian class hitung dapat dijadikan ekstensi atau plugin untuk digunakan oleh class-class yang membutuhkan operasi matematika, dan class yang menggunakannya sebagai extend, dapat meng override fungsi-fungsi di dalam class tersebut untuk digunakan sebebas-bebasnya.

Disebut closed dalam artian class hitung tidak boleh dimodifikasi, dan class hitung membatasi tipe-tipe data yang diterimanya(misal melalui constructor) dan membatasi tipe data yang dikeluarkannya(return). Karena dengan merubah class hitung, dapat membahayakan class-class lain yang juga menggunakan class hitung.


3.Liskov Substitution Principle

Ketika class yang Anda buat, mengextends atau mengimplements dari class lain, pastikan semua function dari class induknya, dapat digunakan oleh class anaknya, dan class induk tidak perlu tahu class-class apa saja yang akan menjadi anaknya. Misal sebagai berikut

public class Burung{
   public void makan(){}
   public void terbang(){}
}

public class BurungGereja extends Burung{}

Class Burung mempunyai function terbang, ketika digunakan oleh class BurungGereja maka class tersebut bisa menggunakan function terbang dan makan juga. Tetapi lihatlah contoh dibawah ini

public class BurungOnta extends Burung{}

Kelihatannya benar, tetapi class BurungOnta tidak bisa menggunakan function terbang, sehingga hanya function makan yang bisa digunakan, maka solusinya adalah sebagai berikut

public class Burung{
   public void makan(){}
}
public class BurungTerbang extends Burung{
   public void terbang(){}
}

public class BurungGereja extends BurungTerbang{}

public class BurungOnta extends Burung{}

Dengan membagi class menjadi hirarki-hirarki, class-class lain bisa mengextends sesuai keperluannya, dalam kasus ini yaitu class BurungGereja mengextends class BurungTerbang, karena class tersebut butuh function makan dan terbang, sementara class BurungOnta mengextends class Burung, karena class tersebut butuh function makan saja.

4.Interface Segregation Principle

Yaitu suatu class yang mengimplements suatu interface, tidak dipaksa untuk mengimplemen function interface yang tidak dibutuhkan. Contohnya seperti di bawah ini

public interface atlit {

void berenang();

void berlari();

void lompatjauh();

void mulai();

}

public atlit_renang implements atlit(){


public void mulai(){

}

public void berenang(){

}

public void berlari(){

}

public void lompatjauh(){

}

}

Class atlit_renang tidak membutuhkan void berlari atau lompat jauh, tetapi karena dia mengimplements class atlit maka terpaksa dia menyediakannya. Maka akan lebih baik jika dipisah menjadi cabang_renang seperti contoh dibawah ini

public interface atlit {

void mulai();

}

public interface cabang_renang extends atlit {

void berenang();

}

public atlit_renang implements cabang_renang(){

public void mulai(){

}

public void berenang(){

}

}

Dengan begini, class atlit_renang hanya menggunakan void berenang dan void mulai, sesuai dengan kebutuhannya


5.Dependency Inversion Principle

Prinsip ini memiliki dua poin, yaitu :

1. Class induk atas tidak bergantung dengan class anak,  dan kedua class seharusnya bergantung pada class abstraksi

2. Class abstraksi seharusnya tidak perlu mengetahui hal-hal detail, karena class yang memakai class abstraksi lah yang seharusnya menyediakan info detail

Untuk lebih memahaminya, lihatlah contoh di bawah ini

public class pertempuran {

pasukan_panah pp = new pasukan_panah();
pasukan_berkuda pb = new pasukan_berkuda();

pp.memanah();
pb.berkuda();

}

Pada contoh di atas, class pertempuran bergantung pada class anak yaitu class pasukan_panah dan pasukan_berkuda, kemudian bergantung pada function memanah dan berkuda(), apabila terjadi perubahan atau dihapusnya class pasukan_panah, maka skrip di class pertempuran juga harus dirubah, hal ini melanggar prinsip dependency inversion. Maka untuk solusinya adalah dengan sebagai berikut.

public interface pasukan {

void menyerang();

}

class pasukan adalah class abstraksi, dia tidak perlu mengetahui hal-hal detail, tidak perlu tahu siapa saja jenis pasukannya dan apa saja metode penyerangannya, dia hanya menyediakan void menyerang dan hanya tahu bahwa gunanya pasukan adalah untuk menyerang.

public pasukan_panah implements pasukan {

public void menyerang(){

memanah();

}

public void memanah(){

}

}
public pasukan_berkuda implements pasukan {

public void menyerang(){

berkuda();

}

public void berkuda(){

}

}

class pasukan_panah dan pasukan_berkuda lah yang mengimplements class pasukan dan kedua class ini yang membeberkan secara detail bagaimana taktik penyerangannya


public class pertempuran {

List pasukan_list;

public pertempuran(List pasukan_list){
 this.pasukan_list = pasukan_list;
}

public void  mulai_pertempuran(){

pasukan_list.forEach(p->p.menyerang());

}

}

Dengan begini, class pertempuran tidak perlu tahu jenis-jenis pasukan dan metode penyerangannya, sehingga apabila class pasukan_panah dihapus maka skrip class pasukan tidak perlu diganti.

Itulah lima poin SOLID yang harus kita terapkan pada kodingan kita, sehingga class-class yang kita buat, mudah untuk dikembangkan dan dites. Maka jangan lagi bebankan tugas yang banyak pada satu class, pecah-pecahlah fungsi-fungsinya, agar classnya tidak "gendut".

Itu saja yang bisa saya bahas di sini, silahkan ikut diskusi di kolom komentar di bawah ini, syukron



Tidak ada komentar:

Catatan: Hanya anggota dari blog ini yang dapat mengirim komentar.

Diberdayakan oleh Blogger.