Menulis Clean Code: Prinsip Liskov Substitution Principle (LSP) Pada SOLID

Prinsip Liskov Substitution Principle (LSP) Pada SOLID
Pada prinsip  Liskov Substitution Principle (LSP) objek dari subclass harus dapat menggantikan objek dari superclass tanpa mengubah keakuratan program. Hal ini mencegah adanya perilaku tak terduga ketika menggunakan turunan kelas.

Ilustrasi Prinsip Liskov Substitution Principle (LSP) Pada SOLID (Gak nyambung sih)

Java mendukung prinsip ini dengan polimorfisme. Jika Anda memiliki superclass atau interface, maka objek dari subclass harus dapat menggantikannya tanpa mengubah perilaku program. Misalnya, jika Rectangle adalah superclass, subclass Square harus memenuhi kontrak yang sama agar tidak ada efek samping yang tidak diinginkan saat digunakan.

Contoh Implementasi LSP Pada Java

Catatan: Rectangle = Persegi Panjang, dan Square = Kotak

Berikut adalah contoh kasus nyata penerapan Liskov Substitution Principle (LSP) dalam Java. Prinsip ini menyatakan bahwa subclass harus dapat menggantikan superclass-nya tanpa mengubah perilaku yang diharapkan. Artinya, objek dari kelas turunan harus bisa digunakan sebagai pengganti objek dari kelas induk tanpa masalah atau efek samping.

Misalkan kita memiliki sistem untuk menghitung area bentuk-bentuk geometris, seperti persegi panjang (Rectangle) dan persegi/kotak (Square). Kelas Rectangle awalnya dirancang sebagai berikut: 

public class Rectangle {
protected int width;
protected int height;

public int getWidth() {
return width;
}

public void setWidth(int width) {
this.width = width;
}

public int getHeight() {
return height;
}

public void setHeight(int height) {
this.height = height;
}

public int getArea() {
return width * height;
}
}

Masalah ketika Square Mewarisi Rectangle

 Ilustrasi untuk Square dan Rectangle

Kita mungkin berpikir untuk membuat Square sebagai subclass dari Rectangle, karena secara umum persegi adalah jenis persegi panjang dengan sisi yang sama panjang.
public class Square extends Rectangle {
@Override
public void setWidth(int width) {
this.width = width;
this.height = width; // memastikan lebar = tinggi
}

@Override
public void setHeight(int height) {
this.width = height; // memastikan lebar = tinggi
this.height = height;
}
}

Namun, ini melanggar prinsip LSP. Seorang pengguna mungkin mengharapkan Rectangle dan Square untuk berperilaku sama ketika diperlakukan sebagai Rectangle, tetapi Square tidak berperilaku seperti yang diharapkan. Misalnya, saat kita mencoba menetapkan lebar dan tinggi yang berbeda pada objek Square, ia akan mengubah kedua nilai secara bersamaan, yang bertentangan dengan perilaku Rectangle.

Contoh Pelanggaran LSP dalam Penggunaan

public class Main {
public static void main(String[] args) {
Rectangle rectangle = new Rectangle();
rectangle.setWidth(5);
rectangle.setHeight(10);
System.out.println("Area persegi panjang: " + rectangle.getArea()); // Output: 50

Rectangle square = new Square();
square.setWidth(5);
square.setHeight(10);
System.out.println("Area persegi: " + square.getArea()); // Output tidak sesuai: 100
}
}

Pada contoh di atas, kita mengharapkan square berperilaku seperti rectangle dan memberikan area 50 saat kita menetapkan lebar 5 dan tinggi 10, tetapi hasilnya adalah 100, karena Square mengatur lebar dan tinggi secara bersamaan. Ini melanggar LSP karena Square tidak mempertahankan kontrak perilaku yang diharapkan dari Rectangle.

Solusi yang Mematuhi LSP adalah Alih-alih menjadikan Square sebagai subclass dari Rectangle, kita bisa membuat Rectangle dan Square sebagai kelas yang terpisah dan mengimplementasikan antarmuka yang sama, misalnya Shape.


public interface Shape {
int getArea();
}

public class Rectangle implements Shape {
protected int width;
protected int height;

public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}

@Override
public int getArea() {
return width * height;
}
}

public class Square implements Shape {
protected int side;

public Square(int side) {
this.side = side;
}

@Override
public int getArea() {
return side * side;
}
}

Dalam penggunaan sekarang, kita bisa menggunakan Rectangle dan Square tanpa melanggar LSP karena mereka tidak lagi terikat dalam hierarki pewarisan yang menyebabkan perilaku tidak konsisten.

public class Main {
public static void main(String[] args) {
Shape rectangle = new Rectangle(5, 10);
System.out.println("Area persegi panjang: " + rectangle.getArea()); // Output: 50

Shape square = new Square(5);
System.out.println("Area persegi: " + square.getArea()); // Output: 25
}
}

Dengan desain ini maka

LSP terpenuhi karena Rectangle dan Square memiliki perilaku independen yang konsisten sesuai dengan bentuknya masing-masing.

Tidak ada perubahan atau efek samping yang tidak diinginkan saat kita mengganti Rectangle dengan Square dalam konteks Shape.

Kode lebih mudah dipahami dan dipelihara, dengan perilaku yang jelas dan sesuai dengan prinsip KISS.

Liskov Substitution Principle (LSP) sangat berhubungan dengan KISS (Keep It Simple, Stupid) karena penerapan LSP membantu menjaga kode tetap sederhana, terstruktur, dan mudah dipahami. Berikut beberapa cara di mana LSP mendukung prinsip KISS:

Membuat Kode Konsisten dan Diprediksi

Dengan mengikuti LSP, kita memastikan bahwa kelas turunan dapat menggantikan kelas induknya tanpa perilaku yang tidak konsisten atau mengejutkan. Hal ini membuat kode lebih diprediksi dan mudah dipahami, sesuai dengan prinsip KISS.

Menghindari Kompleksitas yang Tidak Diperlukan:

LSP membantu menghindari logika tambahan atau pengecekan kondisi untuk menangani perilaku kelas turunan yang berbeda dari kelas induk. Contohnya pada kasus Square dan Rectangle, ketika Square tidak dipaksakan untuk mewarisi Rectangle, kode tidak perlu if-else tambahan untuk membedakan keduanya. Ini membuat kode lebih sederhana dan bersih.

Mendukung Pemahaman dan Pemeliharaan yang Lebih Mudah:

Saat LSP dipatuhi, setiap kelas memiliki tanggung jawab yang jelas dan terpisah, serta perilaku yang sesuai dengan kontraknya. Dengan begitu, kode menjadi lebih mudah dipahami, karena kita bisa yakin bahwa kelas turunan berperilaku sesuai dengan kelas induknya tanpa kejutan, sesuai dengan prinsip KISS yang menekankan kesederhanaan dalam pemahaman.

Meminimalkan Risiko Bug:

Kelas yang mematuhi LSP cenderung bebas dari bug yang disebabkan oleh perilaku tidak terduga ketika mengganti kelas induk dengan kelas turunan. Hal ini membuat kode lebih stabil dan lebih mudah untuk diuji, sesuai dengan tujuan KISS untuk menjaga kode tetap sederhana dan mudah diuji.

Secara keseluruhan, LSP mendukung KISS dengan memastikan bahwa kelas dan subclass memiliki perilaku yang konsisten, mudah dipahami, dan bebas dari kompleksitas yang tidak perlu. Dengan mematuhi LSP, kita menjaga kode tetap sederhana dan mudah dipelihara, yang merupakan inti dari prinsip KISS.


Artikel ini terkait dengan: menulis clean code dengan prinsip solid dan kiss

Related Article:

1. Menulis clean code dengan prinsip solid dan kiss

2. Menulis Clean Code: Prinsip Single Responsibility Principle (SRP) pada SOLID

3. Menulis Clean Code Dengan Open Closed Principle 

4. Menulis Clean dengan Interface Segregation Principle

5. Menulis Clean Code: Prinsip Dependency Inversion Principle (DIP) Pada SOLID

6. Prinsip Liskov Substitution Principle (LSP) Pada SOLID


Comments

Popular posts from this blog

Numpang Kerja Remote dari Bandung Creative Hub

Numpang Kerja Remote dari Bandung Digital Valley

Cara Decompile berkas Dex dan Apk Android