Prinsip Liskov Substitution


Liskov Substitution Principle (LSP) merupakan prinsip ketiga dari perancangan class dalam pemrograman berbasis objek. Seperti yang disampaikan pertama kali oleh Barbara Liskov tahun 1988, LSP menganut prinsip:

Methods that use references to the base classes must be able to use the objects of the derived classes without knowing it

Untuk mendukung prinsip tersebut, maka struktur rancangan antara class induk dan class turunannya harus dapat menyediakan mekanisme method yang dapat dipanggil tanpa perlu “rasa takut” dari dalam method yang menerima parameter referensi dari class induk. Untuk memudahkan, kita dapat melihat contoh struktur class berikut ini yang dapat dikatakan melanggar prinsip LSP:

Kendaraan.java

package com.wordpress.budsus.nonlsp;

public abstract class Kendaraan {
	protected int jarakTempuh = 0;
	protected int gigi = 0;

	public abstract void pindahGigi(int gigi);
	public abstract void laju();

	public int getGigi() {
		return this.gigi;
	}
	public int getJarakTempuh(){
		return this.jarakTempuh;
	}
}

Sepeda.java

package com.wordpress.budsus.nonlsp;

public class Sepeda extends Kendaraan {

	@Override
	public void pindahGigi(int gigi) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void laju() {
		jarakTempuh += 20;
	}
}

Mobil.java

package com.wordpress.budsus.nonlsp;

public class Mobil extends Kendaraan {

	@Override
	public void pindahGigi(int gigi) {
		super.gigi = gigi;
	}

	@Override
	public void laju() {
		jarakTempuh += 60;
	}

}

TestNonLsp.java 

package com.wordpress.budsus.nonlsp;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class TestNonLsp {

	@Test
	public void test() {
		ArrayList<Kendaraan> o = new ArrayList<Kendaraan>();
		o.add(new Sepeda());
		o.add(new Mobil());
		o.add(new Mobil());
		TestNonLsp.tryMethod(o);
	}

	public static void tryMethod(List<Kendaraan> k) {
		for(Kendaraan kend:k) {
			kend.pindahGigi(2);
			kend.laju();
			assertEquals("Gigi 2", 2, kend.getGigi());
		}
	}

}

Struktur class Kendaraan menjadi tidak transparan terhadap class Sepeda, karena class Sepeda tidak memiliki karakteristik pindahGigi(). Dengan keadaan ini, ketika dipanggil dari pada method tryMethod() di jUnit class akan mengakibatkan kesalahan. Untuk mencegah hal ini, ada baiknya memang dibuatkan dua buah kelas kendaraan, yaitu yang memiliki karakteristik mesin dan non mesin.

Kendaraan.java

package com.wordpress.budsus.lsp;

public abstract class Kendaraan {
	protected int jarakTempuh = 0;
	public abstract void laju();

	public int getJarakTempuh(){
		return this.jarakTempuh;
	}
}

Bermotor.java

package com.wordpress.budsus.lsp;

public class Bermotor extends Kendaraan {
	protected int gigi = 0;

	public void pindahGigi(int gigi) {
		this.gigi = gigi;
	}

	public int getGigi() {
		return this.gigi;
	}

	@Override
	public void laju() {
	}

}

Nonmotor.java

package com.wordpress.budsus.lsp;

public class NonMotor extends Kendaraan {

	@Override
	public void laju() {
	}

}

Sepeda.java

package com.wordpress.budsus.lsp;

public class Sepeda extends NonMotor {
	@Override
	public void laju() {
		jarakTempuh += 20;
	}
}

Mobil.java

package com.wordpress.budsus.lsp;

public class Mobil extends Bermotor {
	@Override
	public void laju() {
		jarakTempuh += 60;
	}

}

TestLsp.java

package com.wordpress.budsus.lsp;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class TestLsp {

	@Test
	public void test() {
		ArrayList<Bermotor> o = new ArrayList<Bermotor>();
		o.add(new Mobil());
		o.add(new Mobil());
		TestLsp.tryMotor(o);
		ArrayList<NonMotor> s = new ArrayList<NonMotor>();
		s.add(new Sepeda());
		s.add(new Sepeda());
		TestLsp.tryNonMotor(s);
	}

	public static void tryMotor(List<Bermotor> k) {
		for(Bermotor kend:k) {
			kend.pindahGigi(2);
			kend.laju();
			assertEquals("Gigi 2", 2, kend.getGigi());
		}
	}
	public static void tryNonMotor(List<NonMotor> k) {
		for(NonMotor kend:k) {
			kend.laju();
		}
	}

}