Langsung ke konten utama

SOLID - Prinsip Desain Arsitektur Di Dalam Pemrograman Object Oriented (Liskov's Substitution Principal)

Liskov's Subtitution Principal

Pada prinsip ketiga ini, berkaitan erat dengan prinsip kedua yaitu Open / CLose Principal, namun lebih fokus terhadap behaviour antara Parent Class dan Child Class.

Let Î¦(x) be a property provable about objects x of type T. Then Î¦(y) should be true for objects y of type S where S is a subtype of T

 bingung ? oke kira-kira simpelnya gini: 

Object dari Parent Class bisa diganti dengan Object dari Child Class tanpa merusak aplikasi / membuat aplikasi berhenti (error)

Jadi suatu object dari Parent Class atau turunannya, harus bisa dengan mudah diganti dengan Object / Instance dari Class Turunan tanpa mengganggu jalannya program. Kita bisa menerapkan konsep ini dengan menggunakan abstraksi / interface. Kalau masih bingung, mari kita belajar langsung dengan contoh.

Contoh Kasus

Bayangkan kita punya 1 soket lampu di teras rumah yang mati dan akan kita ganti dengan yang baru. Lampu yang kita gunakan sebelumnya adalah bohlam lampu pijar yang fungsinya adalah untuk penerangan. Karena gunanya untuk penerangan, mungkin bisa saja kita ganti dengan lampu warna warni namun tidak sesuai dengan kegunaannya. Akan lebih tepat jika kita ganti dengan lampu LED yang memang kegunaannya untuk penerangan. Dari analogi ini, kita akan membuat Class Lampu yang akan mempunyai beberapa Class turunan yaitu Class LampuPijar, LampuLED, dan LampuDisko. Kemudian saya juga punya Class SocketLampuTeras yang digunakan untuk menyalakan lampu.
<?php

namespace Kematjaya\PhpLsp\Lampu;

/**
 * Description of AbstractLampu
 *
 * @author programmer
 */
abstract class AbstractLampu 
{
    abstract public function nyalakan();
}
<?php

namespace Kematjaya\PhpLsp\Lampu;

/**
 * Description of LampuPijar
 *
 * @author programmer
 */
class LampuPijar extends AbstractLampu 
{
    public function nyalakan() 
    {
        return "Nyala Terang";
    }

}
<?php

namespace Kematjaya\PhpLsp\Lampu;

/**
 * Description of LampuLED
 *
 * @author programmer
 */
class LampuLED extends AbstractLampu 
{
    public function nyalakan() 
    {
        return "Nyala Terang";
    }

}
<?php

namespace Kematjaya\PhpLsp\Lampu;

/**
 * Description of LampuDisko
 *
 * @author programmer
 */
class LampuDisko extends AbstractLampu 
{
    
    public function nyalakan() 
    {
        return "Nyala Kelap Kelip";
    }

}
<?php

namespace Kematjaya\PhpLsp;

use Kematjaya\PhpLsp\Lampu\AbstractLampu;

/**
 * Description of SocketLampuTeras
 *
 * @author programmer
 */
class SocketLampuTeras 
{
    private AbstractLampu $lampu;
    
    public function __construct(AbstractLampu $lampu) 
    {
        $this->lampu = $lampu;
    }
    
    public function gantiLampu(AbstractLampu $lampu):self
    {
        $this->lampu = $lampu;
        
        return $this;
    }
    
    public function on():string 
    {
        return $this->lampu->nyalakan();
    }
}
dari contoh diatas, bisa saja lampuPijar kita ganti dengan LampuDisko. Namun setelah dilakukan testing maka hasilnya seperti berikut:
<?php

namespace Kematjaya\PhpLsp\Tests;

use Kematjaya\PhpLsp\Lampu\LampuDisko;
use Kematjaya\PhpLsp\Lampu\LampuLED;
use Kematjaya\PhpLsp\Lampu\LampuPijar;
use Kematjaya\PhpLsp\SocketLampuTeras;
use PHPUnit\Framework\TestCase;

/**
 * Description of LampuTamanTest
 *
 * @author programmer
 */
class LampuTamanTest extends TestCase 
{
    public function testNyalakanLampu()
    {
        $pijar = new LampuPijar();
        $socket = new SocketLampuTeras($pijar);
        $this->assertEquals("Nyala Terang", $socket->on());
        
        $socket->gantiLampu(new LampuLED());
        $this->assertEquals("Nyala Terang", $socket->on());
        
        $socket->gantiLampu(new LampuDisko());
        $this->assertEquals("Nyala Terang", $socket->on());
    }
}

dari testing diatas, didapatkan hasil yang kurang sesuai karena peruntukannya untuk penerangan. Ini bisa anggap bug karena hasil yang kurang sesuai dengan yang diharapkan. Oleh karena itu kita perlu buat beberapa modifikasi pada kode Class SocketLampuTeras nya dengan menambahkan Interface / Abstract Class seperti kode berikut.
<?php

namespace Kematjaya\PhpLsp\Lampu;

/**
 * Description of AbstractLampuPenerangan
 *
 * @author programmer
 */
abstract class AbstractLampuPenerangan extends AbstractLampu 
{
    public function nyalakan()
    {
        return "Nyala Terang";
    }
}
<?php

namespace Kematjaya\PhpLsp\Lampu;

/**
 * Description of AbstractlampuHiburan
 *
 * @author programmer
 */
abstract class AbstractlampuHiburan extends AbstractLampu 
{
    public function nyalakan() 
    {
        return "Nyala Kelap Kelip";
    }
}
Kemudian kita ubah Class LampuDisko menjadi turunan dari Class AbstractLampuHiburan
<?php

namespace Kematjaya\PhpLsp\Lampu;

/**
 * Description of LampuDisko
 *
 * @author programmer
 */
class LampuDisko extends AbstractlampuHiburan 
{

}
dan Class LampuPijar dan LampuLED menjadi turunan Class AbstractLampuPenerangan
<?php

namespace Kematjaya\PhpLsp\Lampu;

/**
 * Description of LampuLED
 *
 * @author programmer
 */
class LampuLED extends AbstractLampuPenerangan 
{

}

class LampuPijar extends AbstractLampuPenerangan
{
    
}

Kemudian kita ubah Class SocketLampuTeras
<?php

namespace Kematjaya\PhpLsp;

use Kematjaya\PhpLsp\Lampu\AbstractLampuPenerangan;


/**
 * Description of SocketLampuTeras
 *
 * @author programmer
 */
class SocketLampuTeras 
{
    private AbstractLampuPenerangan $lampu;
    
    public function __construct(AbstractLampuPenerangan $lampu) 
    {
        $this->lampu = $lampu;
    }
    
    public function gantiLampu(AbstractLampuPenerangan $lampu):self
    {
        $this->lampu = $lampu;
        
        return $this;
    }
    
    public function on():string 
    {
        return $this->lampu->nyalakan();
    }
}

karena di Class SocketLampuTeras kita spesifik menggunakan class AbstractLampuPenerangan, maka class LampuDisko tidak bisa kita masukkan sebagai lampu di socket ini, jadi testing kita menjadi seperti ini.
<?php

namespace Kematjaya\PhpLsp\Tests;

use Kematjaya\PhpLsp\Lampu\LampuDisko;
use Kematjaya\PhpLsp\Lampu\LampuLED;
use Kematjaya\PhpLsp\Lampu\LampuPijar;
use Kematjaya\PhpLsp\SocketLampuTeras;
use PHPUnit\Framework\TestCase;

/**
 * Description of LampuTamanTest
 *
 * @author programmer
 */
class LampuTamanTest extends TestCase 
{
    public function testNyalakanLampu()
    {
        $pijar = new LampuPijar();
        $socket = new SocketLampuTeras($pijar);
        $this->assertEquals("Nyala Terang", $socket->on());
        
        $socket->gantiLampu(new LampuLED());
        $this->assertEquals("Nyala Terang", $socket->on());
    }
}
setelah dilakukan beberapa modifikasi, sekarang kita jalankan lagi unit test nya, maka hasilnya seperti berikut:

Kesimpulan

LSP bertujuan untuk menghindari error / bug ketika suatu object diganti dengan object yang lain. Karena itu LSP mengharuskan agar suatu object mempunyai perilaku yang sama dengan object yang digantikan. Untuk mencapai tujuan ini, kita bisa menggunakan abstraksi / interface untuk memastikan object mempunyai perilaku yang sama sehingga tidak mengganggu jalannya program.

Kira-kira cukup sekian ya tulisan ini. Jika ada yang perlu diperbaiki, bisa tulis di komentar

Komentar

Postingan populer dari blog ini

Contoh Perhitungan Algoritma Perceptron

      Melanjutkan tulisan saya sebelumnya tentang algoritma perceptron,kali ini saya akan menulis tentang conto perhitungan manual algoritma perceptron. Untuk contoh kasusnya saya menggunakan data logika AND. Cekidot.... Algoritma      Data yang kita gunakan sebagai contoh adalah data logika AND sebagai berikut: x1 x2 target 0 0 0 0 1 0 1 0 0 1 1 1       tentukan bobot awal secara acak, saya pakai contoh w1 = 0,w2 =0, learning rate = 1, bias = 0,maksimal epoh = 10. Disini saya memakai fungsi aktivasi undak biner. Epoh ke 1 Data ke satu x = {0,0}, bobot w = {0,0},b=0,target = 0 y_in = (x1*w1)+(x2*w2)+b = (0*0)+(0*0)+0 = 0 y = sign(0) = 1 karena y != target maka hitung error dan update bobot  error = target - y = 0 - 1 = -1 w1_baru = w1_lama +(learning_rate*error*x1)                = 0 ...

Contoh Perhitungan Algoritma Learning Vector Quantization

Melanjutkan tulisan saya tentang algoritma Learning Vector Quantization yang lalu, kali ini saya akan melanjutkan dengan contoh perhitungan manual. Berikut ini contoh data yang akan kita hitung. No X1 X2 X3 X4 target 1 0 1 1 0 0 2 0 0 1 1 1 3 1 1 1 1 0 4 1 0 0 1 1 pada contoh di atas, saya menggunakan 4 data sebagai data training beserta target yang bertujuan untuk mendapatkan bobot yang akan digunakan pada proses klasifikasi. Bobot awal adalah { 1, 1, 1, 0} dan { 1, 0, 1, 1} dengan learning rate 0,05 dengan fungsi pembelajaran = 0,1. Pelatihan Iterasi ke 1 1. Data ke 1 { 0, 1, 1, 0} dengan target 0, bobot = {{ 1, 1, 1, 0},{ 1, 0, 1, 1}}      - menghitung bobot untuk masing masing output :          kelas 0 = sqrt(((0-1)^2)+((1-1)^2)+((1-1)^2)+((0-...

Part 7 : Normalisasi Histogram

Menyambung tulisan saya yang sebelumnya tentang pengolahan citra khususnya histogram,kali ini saya lanjutkan tentang Normalisasi histogram.Sebelumnya saya harap agan sudah mengerti tentang histogram.Jika belum bisa di baca dulu di tulisan saya sebelumnya di sini . Normalisasi Histogram adalah menskalakan nilai piksel secara linear untuk menggunakan secara penuh jangkauan yang tersedia. Rumus :  Keterangan : n k= nilai grayscale dari piksel ke k(k = 0,1,2,3....) min = nilai grayscale terkecil yang diperoleh dari histogram max = nilai grayscale terbesar L = range nilai grayscale citra Contoh perhitungan : dari tabel di atas,nilai min adalah 2 yaitu nilai grayscale terkecil dari citra dan max adalah 5 s = 0 - 2 /5 - 2 =0 (untuk n = 0)  hasil = 0 x 7(nilai maksimal grayscale) = 0 sk = 3 - 2 /5 - 2 = 0.333  (untuk n = 3) hasil = 0.333 x 7 = 2 keterangan : 7 adalah range grayscale dari citra,dan untuk banyak kasus biasanya memakai 255. Tujuan Normalisasi...