![Contoh Proxy Design Pattern](https://images.ctfassets.net/7wjlcr9d5ii8/7mxDYbiEsE11CFpGbxmsrv/8a2e84713ca550a4a281fc4bf0acdd12/proxy.jpeg?w=1024&h=1024&fl=progressive&q=100&fm=jpg&fit=thumb&f=faces)
Design pattern ini seringnya digunakan ketika membuat framework. Beberapa framewrok menggunakan Proxy behind the scene untuk memanipulasi behavior objek. Seperti saat melakukan Autowired pada Spring atau Mock pada Mockito. Framework biasanya menggunakan library dari JDK atau library pihak ketiga seperti CGLIB atau Byte Buddy untuk membuat proxy. Tapi dalam tulisan kali ini gw hanya memberikan contoh menggunakan Proxy sederhana sebagai pembelajaran.
Proxy Design Pattern adalah Structural Design Pattern yang berguna sebagai pengganti objek asli dan memiliki kontrol akses terhadap objek asli tersebut seperti melakukan sesuatu saat sebelum atau sesudah eksekusi objek asli.
Design Pattern
Terdapat sebuah class UserDetailUseCase dari modul luar untuk melakukan print User. Kita tidak memiliki akses untuk melakukan modifikasi terhadap class tersebut karena berasal dari library pihak ketiga.
Class User
public class User{
private final int id;
private final String name;
public User(int id, String name){
this.id = id;
this.name = name;
}
public int getId(){
return id;
}
public String getName(){
return name;
}
}
Interface UserDetail
public interface UserDetail{
void printUserDetail(User user) throws Exception;
}
Class UserDetailUseCase
public class UserDetailUseCase implements UserDetail{
@Override
public void printUserDetail(User user) throws Exception{
System.out.println("user.getName() = " + user.getName());
System.out.println("user.getId() = " + user.getId());
}
}
Contoh penggunaan
public static void main(String[] args) throws Exception{
UserDetail userDetail = new UserDetailUseCase();
userDetail.printUserDetail(new User(11, "ferry"));
}
Misalkan selanjutnya kita ingin menambahkan validasi User sebelum eksekusi print. Seperti yang sudah dijelaskan di atas, kita tidak mempunyai akses terhadap class UserDetailUseCase tersebut. Jadi kita tidak bisa melakukan modifikasi karena class tersebut berasal dari library pihak ketiga🤔.
Solusi untuk kasus di atas adalah kita membuat class Proxy agar bisa dimodifikasi. Sekarang kita praktekkan Proxy Design Pattern😎.
Class UserDetailProxy
public class UserDetailProxy extends UserDetailUseCase{
private static UserDetailUseCase userDetailUseCase = null;
@Override
public void printUserDetail(User user) throws Exception{
if(userDetailUseCase == null){
userDetailUseCase = new UserDetailUseCase();
}
if(user == null){
throw new Exception("user can't be null");
}
if(user.getId() < 1){
throw new Exception("id can't be less than 1");
}
if(user.getName() == null){
throw new Exception("name can't be null");
}
userDetailUseCase.printUserDetail(user);
}
}
Contoh Penggunaan
public static void main(String[] args) throws Exception{
UserDetail userDetail = new UserDetailProxy();
userDetail.printUserDetail(new User(11, "ferry"));
}
Dengan Proxy sekarang kita bisa memodifikasi behavior UserDetailUseCase tanpa harus melakukan modifikasi langsung pada objjek yang berasal dari library pihak ketiga meskipun kita tidak punya akses melakukan perubahan pada class tersebut. Kita juga bisa melakukan caching objek di dalam class proxy agar objek asli dari UserDetailUseCase hanya dibuat satu kali saat pertama kali diakses saja. Tapi itu optional sih, ga di-cache jadi static pun ga masalah.
Proxy Design Pattern biasanya digunakan pada framework/library. Contohnya Mockito, saat melakukan mock, mockito ga punya akses langsung pada class yang kita punya untuk mocking objek. Oleh karena itu Mockito membuat Proxy class agar behavior dari objek asli bisa dimodifikasi tanpa harus mengubah langsung pada objek asli tersebut.
Proxy Design Pattern membuat subclass dari objek asli agar objek asli bisa dimodifikasi secara tidak langsung. Contoh yang paling umum adalah pada framework. Framework dapat melakukan modifikasi pada objek asli yang kita punya lewat Proxy. Framework melakukannya lewat library seperti CGLIB, Byte Buddy, atau JDK Dynamic Proxy. Kebetulan contoh di atas kita melakukannya manual, secara sederhana agar dapat dipahami dengan mudah untuk pemula. Jadi agak berbeda dengan implementasi yang dilakukan oleh framework. Mungkin di lain kesempatan gw bakal bikin contoh menggunakan CGLIB atau Byte Buddy. Secara struktur, Proxy memang memiliki kemiripan dengan Decorator Design Pattern. Bedanya, User memiliki kontrol penuh terhadap objek asli pada Decorator. Sedangkan pada Proxy, kontrol penuh terhadap objek asli dilakukan di dalam komponen Proxy. Goalsnya pun berbeda, pada Proxy goalsnya adalah kita menyisipkan behavior tertentu saat mengeksekusi behavior objek asli. Sedangkan pada Decorator goalsnya adalah mengganti behavior pada objek asli.