Pemrograman · Pola desain
Penjelasan pola Proxy beserta contohnya
Jawaban singkat
Proxy adalah pola desain struktural yang menyediakan objek pengganti dengan interface yang sama seperti objek asli, sehingga proxy dapat mengontrol akses ke objek asli itu. Klien berbicara dengan proxy seolah-olah itu objek aslinya, dan proxy menentukan kapan serta bagaimana meneruskan setiap panggilan. Jenis yang umum adalah virtual proxy (pembuatan lazy), protection proxy (pemeriksaan akses), caching proxy, dan remote proxy.
Tujuan dan masalah yang diselesaikan
Tujuan: menyediakan pengganti atau placeholder bagi objek lain untuk mengontrol akses ke objek tersebut. Proxy adalah salah satu pola struktural dalam buku Gang of Four (GoF).
Misalkan sebuah aplikasi memanggil layanan cuaca lewat jaringan. Setiap panggilan memakan ratusan milidetik dan berbiaya, sementara kota yang sama sering diminta berkali-kali per menit. Anda tidak bisa mengubah class layanan itu, dan Anda tidak ingin menambahkan kode caching di setiap tempat yang memanggilnya. Proxy menyelesaikan hal ini: ia mengimplementasikan interface yang sama, menyimpan cache, dan hanya memanggil layanan asli saat cache tidak berisi data. Pemanggil tidak perlu berubah sama sekali.
Gagasan yang sama mencakup kebutuhan lain: membuat objek yang mahal hanya saat pertama kali dipakai, memeriksa izin sebelum panggilan, mencatat setiap panggilan, atau menyembunyikan fakta bahwa objek aslinya berada di mesin lain.
Struktur dan peserta
| Peran | Tanggung jawab |
|---|---|
| Subject | Interface yang dipakai bersama oleh objek asli dan proxy, sehingga klien bisa memakai salah satunya |
| Real subject | Objek yang melakukan pekerjaan sebenarnya |
| Proxy | Mengimplementasikan interface subject, menyimpan atau membuat referensi ke real subject, dan menambahkan logika kontrol sebelum atau sesudah meneruskan panggilan |
| Client | Hanya bekerja dengan interface subject dan tidak tahu apakah ia memegang proxy |
| Jenis proxy | Apa yang dikontrol |
|---|---|
| Virtual proxy | Menunda pembuatan objek yang mahal sampai objek itu dibutuhkan |
| Protection proxy | Memeriksa apakah pemanggil diizinkan menjalankan suatu operasi |
| Caching proxy | Menyimpan hasil dan mengembalikannya untuk permintaan yang berulang |
| Remote proxy | Mewakili objek di proses atau mesin lain dan menangani komunikasinya |
| Logging proxy | Mencatat panggilan dan argumen tanpa mengubah objek asli |
Implementasi TypeScript: caching proxy
WeatherService adalah subject. CachedWeatherService adalah proxy: ia punya method yang sama dan hanya meneruskan ke layanan asli saat nilai di cache tidak ada atau sudah terlalu lama.
interface WeatherService {
getTemperature(city: string): Promise<number>;
}
class RemoteWeatherService implements WeatherService {
calls = 0;
async getTemperature(city: string): Promise<number> {
this.calls++; // imagine a slow HTTP request here
return city.length * 3;
}
}
class CachedWeatherService implements WeatherService {
private cache = new Map<string, { value: number; time: number }>();
constructor(private real: WeatherService, private maxAgeMs = 60_000) {}
async getTemperature(city: string): Promise<number> {
const hit = this.cache.get(city);
if (hit && Date.now() - hit.time < this.maxAgeMs) return hit.value;
const value = await this.real.getTemperature(city);
this.cache.set(city, { value, time: Date.now() });
return value;
}
}
async function main() {
const real = new RemoteWeatherService();
const weather: WeatherService = new CachedWeatherService(real);
await weather.getTemperature("Paris");
await weather.getTemperature("Paris");
console.log(await weather.getTemperature("Hanoi"), "real calls:", real.calls);
// 15 real calls: 2
}
main();Variabel client bertipe WeatherService, jadi Anda bisa berganti antara layanan asli dan proxy di satu tempat saja, misalnya dalam konfigurasi dependency injection.
Virtual dan protection proxy dengan JavaScript Proxy
JavaScript punya objek Proxy bawaan (ES2015) yang mencegat operasi seperti pembacaan properti, penulisan, dan pemanggilan fungsi lewat fungsi handler yang disebut trap. Ini cara praktis untuk membuat proxy tanpa menulis class untuk setiap interface.
type Account = { owner: string; balance: number };
function readOnly<T extends object>(target: T): T {
return new Proxy(target, {
set(_obj, prop) {
throw new Error("Cannot change " + String(prop) + ": read-only");
},
});
}
const account = readOnly<Account>({ owner: "Ana", balance: 100 });
console.log(account.balance); // 100
try {
account.balance = 0;
} catch (e) {
console.log((e as Error).message); // Cannot change balance: read-only
}Kapan dipakai dan kapan tidak
- Pakai untuk menambahkan lazy loading, kontrol akses, caching, logging, atau akses jarak jauh tanpa mengubah class asli maupun pemanggilnya.
- Pakai bila objek aslinya di luar kendali Anda, seperti class dari library atau klien jaringan.
- Jangan dipakai bila pembungkus fungsi biasa sudah cukup. Untuk satu fungsi, higher-order function seperti
memoize(fn)lebih sederhana daripada sebuah class. - Jangan menyembunyikan panggilan jarak jauh yang lambat atau gagal di balik proxy yang tampak lokal. Pemanggil tetap perlu menangani latensi dan error, jadi buat itu terlihat di interface (misalnya dengan mengembalikan
Promise). - Hati-hati dengan identitas: proxy adalah objek yang berbeda dari real subject, sehingga
proxy === realbernilai false.
Penggunaan di dunia nyata
- Vue 3 membangun sistem reaktivitasnya di atas
ProxyJavaScript: membaca properti mencatat dependensi dan menulisnya memicu pembaruan. - Java menyediakan
java.lang.reflect.Proxyuntuk membuat class proxy dinamis saat runtime; framework memakainya untuk menambahkan transaksi, pemeriksaan keamanan, atau panggilan jarak jauh di sekitar interface. - Object-relational mapper seperti Hibernate mengembalikan lazy proxy untuk entitas terkait dan memuat data aslinya dari database saat pertama kali diakses.
- Library remote procedure call membuat client stub yang tampak seperti objek lokal tetapi mengirim setiap panggilan lewat jaringan.
Pola terkait
| Pola | Perbedaannya dengan Proxy |
|---|---|
| Decorator | Struktur sama, tujuan berbeda: Decorator menambahkan perilaku baru dan sering ditumpuk; Proxy mengontrol akses dan biasanya mengelola siklus hidup objek aslinya. |
| Adapter | Adapter memberi objek interface yang berbeda; Proxy mempertahankan interface yang persis sama. |
| Facade | Facade menawarkan interface baru yang lebih sederhana untuk seluruh subsistem; Proxy menggantikan satu objek. |
| Flyweight | Flyweight membagi objek untuk menghemat memori; virtual proxy menunda pembuatan objek untuk menghemat waktu dan memori. |
FAQ
Apa perbedaan antara Proxy dan Decorator?
Keduanya membungkus objek dengan interface yang sama. Decorator menambahkan tanggung jawab dan biasanya disusun oleh klien, sedangkan proxy mengontrol akses ke objek asli dan sering membuat atau mengelola objek itu sendiri.
Apakah objek Proxy JavaScript sama dengan pola Proxy?
Itu fitur bahasa yang membuat pola ini mudah diimplementasikan. Proxy JavaScript mencegat operasi pada objek target lewat trap, persis seperti yang dilakukan proxy dalam pengertian GoF.
Apa itu virtual proxy?
Virtual proxy menggantikan objek yang mahal untuk dibuat, seperti gambar besar. Ia membuat objek asli hanya saat method yang membutuhkannya pertama kali dipanggil.
Apakah reverse proxy server contoh pola Proxy?
Gagasannya sama di level jaringan: server seperti nginx berada di depan server lain dengan interface HTTP yang sama dan menambahkan caching, kontrol akses, atau load balancing. Pola GoF menjelaskan gagasan yang sama untuk objek dalam satu program.