Apa itu AOP?

Aspect Oriented Programming (AOP)

Secara sederhana AOP (Aspect Oriented Programming) merupakan sebuah metodologi sebagai tambahan untuk melengkapi metodologi OOP, nah mengapa ?
Salah satu alasannya adalah OOP dianggap tidak cukup baik untuk memecahkan masalah crosscutting concern yang umumnya digunakan untuk aplikasi enterprise.
Apa itu crosscutting concern ? Contoh umum crosscutting concern adalah logging, validation, transaction dan sebagainya.

Perbedaan OOP dan AOP

Misal, saya ingin membuat sebuah aplikasi kalkulator untuk melakukan operasi kali dan bagi.
Pertama-tama saya akan membuat sebuah interface untuk melakukan proses penghitungan tersebut.

package org.kris.impl;
import org.kris.interfc.Kalkulator;
public class KalkulatorImpl implements Kalkulator {
	@Override
	public double bagi(double x, double y) {
		double hasil = x * y;
		return hasil;
	}
	@Override
	public double kali(double x, double y) {
		double hasil = x * y;
		return hasil;
	}
}

Nah, di tengah jalan kita ingin menambahkan fitur logging terhadap masing-masing method tersebut.
Oleh karena itu kita harus memasukan fitur-fitur tersebut ke masing-masing method.

import org.kris.interfc.Kalkulator;
public class KalkulatorImpl implements Kalkulator {
	private static final Logger LOGGER=Logger.getLogger(KalkulatorImpl.class);
	@Override
	public double bagi(double x, double y) {
		LOGGER.info("Method bagi dijalankan dengan nilai : "+x+" , "+y);
		double hasil = x / y;
		LOGGER.info("Method bagi selesai dijalankan dengan hasil "+hasil);
		return hasil;
	}
	@Override
	public double kali(double x, double y) {
		LOGGER.info("Method kali dijalankan dengan nilai : "+x+" , "+y);
		double hasil = x * y;
		LOGGER.info("Method kali selesai dijalankan dengan hasil "+hasil);
		return hasil;
	}
}

Lalu kita menambahkan sebuah validasi dalam method “bagi()” dimana fasilitas ini hanya akan melakukan pengecekan apakah pembagi adalah 0.
Jika benar maka akan dilemparkan ke exception.

@Override
public double bagi(double x, double y) {
	LOGGER.info("Method bagi dijalankan dengan nilai : "+x+" , "+y);
	if(y==0){
		throw new IllegalArgumentException("Pembagi Tidak Boleh 0 !");
	}
	double hasil = x / y;
	LOGGER.info("Method bagi selesai dijalankan dengan hasil "+hasil);
	return hasil;
}

Kemudian aplikasi siap di jalankan :

package org.kris.test;
import org.junit.Before;
import org.junit.Test;
import org.kris.impl.KalkulatorImpl;
import org.kris.interfc.Kalkulator;
public class TestKalkulator {
	private Kalkulator kalkulator;
	@Before
	public void init(){
		kalkulator=new KalkulatorImpl();
	}
	@Test
	public void testAllMethod(){
		kalkulator.bagi(2, 2);
		kalkulator.kali(2, 2);
	}
}

Hasilnya :

1. 2009-10-01 15:45:01,409 [main] INFO org.kris.impl.KalkulatorImpl - Method bagi dijalankan dengan nilai : 2.0 , 2.0
2. 2009-10-01 15:45:01,411 [main] INFO org.kris.impl.KalkulatorImpl - Method bagi selesai dijalankan dengan hasil 1.0
3. 2009-10-01 15:45:01,411 [main] INFO org.kris.impl.KalkulatorImpl - Method kali dijalankan dengan nilai : 2.0 , 2.0
4. 2009-10-01 15:45:01,411 [main] INFO org.kris.impl.KalkulatorImpl - Method kali selesai dijalankan dengan hasil 4.0

Pada intinya terdapat dua masalah dalam contoh diatas,

  1. Pada setiap method yang biasa disebut bisnis method(kali,bagi) menjadi tidak bersih, mengapa ? Karena telah disisipi oleh method2 lain yang tidak ada hubungan secara eksplisit dengan busines method, hal ini biasa disebut tanggling.
  2. Apabila kita memiliki sebuah kelas dengan dua buah method maka kita juga akan membuat logging dan validasi yang sama disetiap method tersebut.
    Coba dibayangkan, kita memiliki 100 kelas dan dimasing-masing kelas tersebut terdapat minimal 5 method, dan kita ingin melakukan logging dan validasi, hal ini biasa disebut scattering

Nah, untuk menangani masalah crosscutting concern kita bisa menggunakan dynamic proxy, proxy tersebut akan membungkus object.
Ketika object tersebut dipanggil maka harus melewati proxy terlebih dahulu.
Jadi kita bisa meletakan seluruh masalah crosscutting concerns pada proxy.
Jadi misal kita letakan seluruh kode validasi dan logging kedalam proxy.
Apabila object tersebut dipanggil maka pemanggil akan dikenai validasi dan logging terlebih dahulu,
setelah itu baru pemanggil akan dapat menggunakan object yang sesungguhnya.
Pada saat pemanggil keluar dari proxy pemanggil juga bisa dikenai method tertentu.
Didalam java kita bisa menggunakan static proxy dengan OOP biasa, mari kita buktikan mengacu pada contoh sebelumnya.
Pertama kita buat kelas untuk menangani logging.
Untuk membuat proxy kita dapat membuat static kelas dan meregister object tersebut dengan method getClassLoader(),kemudian untuk melakukan implementasi dari proxy tersebut maka kita menggunakan method getInterface(), Inilah object yang di wrap didalam proxy. Di parameter terakhir adalah untuk memanggil logging handler dari kelas itu sendiri. Untuk menjalankannya maka kita buang saja seluruh logging yang terdapat di dalam kelas KalkulatorImpl. Hasilnya :

package org.kris.impl;
import org.kris.interfc.Kalkulator;
public class KalkulatorImpl implements Kalkulator {
	@Override
	public double bagi(double x, double y) {
		double hasil = x * y;
		return hasil;
	}
	@Override
	public double kali(double x, double y) {
		double hasil = x * y;
		return hasil;
	}
}

Dapat dilihat diatas, methodnya menjadi bersih kembali, kemudian kita jalankan :

package org.kris.test;
import org.junit.Before;
import org.junit.Test;
import org.kris.impl.KalkulatorImpl;
import org.kris.interfc.Kalkulator;
import org.kris.util.KalkulatorLoggingHandler;
public class TestKalkulator {
	private Kalkulator kalkulator;
	@Before
	public void init(){
		kalkulator=(Kalkulator) KalkulatorLoggingHandler.createProxy(new KalkulatorImpl());
	}
	@Test
	public void testAllMethod(){
		kalkulator.bagi(2, 2);
		kalkulator.kali(2, 2);
	}
}

Hasilnya akan sama :

1. 2009-10-01 16:47:25,158 [main] INFO org.kris.util.KalkulatorLoggingHandler - Method bagi dijalankan dengan nilai : [2.0, 2.0]
2. 2009-10-01 16:47:25,161 [main] INFO org.kris.util.KalkulatorLoggingHandler - Method bagi dijalankan dengan hasil : 1.0
3. 2009-10-01 16:47:25,162 [main] INFO org.kris.util.KalkulatorLoggingHandler - Method kali dijalankan dengan nilai : [2.0, 2.0]
4. 2009-10-01 16:47:25,162 [main] INFO org.kris.util.KalkulatorLoggingHandler - Method kali dijalankan dengan hasil : 4.0

Untuk validasi, hampir sama caranya, kita perlu membuat method yang mampu melakukan proses pencocokan/validasi agar jika ada proses yang tidak seharusnya, akan segera dilempar ke exception handler.
Pada testing diatas object dari kalkulator menggunakan implementasinya yaitu KalkulatorImpl.
Dapat kita lihat untuk menggunakannya maka object kalkulator harus melewati kelas KalkulatorValidationHandler dan KalkulatorValidationLogging.
Dimana posisi kelas KalkulatorImpl sekarang ?
Kelas KalkulatorImpl akan di-wrap didalam proxy, oleh karena itu si object kalkulator harus melewati kedua kelas tersebut untuk dapat menggunakan implementasinya.
Nah, dengan menggunakan proxy maka kita dapat menghindari tangling dan scattering.

Kesimpulannya, AOP lebih memperindah (membersihkan) susunan code juga mempermudah bagi user untuk memahami struktur/alur programnya.
Semoga bermanfaat :mrgreen:

Leave a Reply