𝗦𝘁𝗿𝘂𝗰𝘁𝘂𝗿𝗮𝗹 𝗗𝗲𝘀𝗶𝗴𝗻 𝗣𝗮𝘁𝘁𝗲𝗿𝗻𝘀: 𝗙𝗮𝗰𝗮𝗱𝗲, 𝗙𝗹𝘆𝘄𝗲𝗶𝗴𝗵𝘁, 𝗮𝗻𝗱 𝗣𝗿𝗼𝘅𝘆
Structural design patterns help you organize classes and objects.
Today we cover the final three patterns to complete your toolkit.
𝟭. 𝗧𝗵𝗲 𝗙𝗮𝗰𝗮𝗱𝗲 𝗣𝗮𝘁𝘁𝗲𝗿𝗻 Facade simplifies complex systems. It provides one simple interface to a group of messy classes.
Think of a movie theater. To watch a movie, you need to dim lights, start the projector, and open curtains. Instead of calling five different systems, you call one method: theater.watch_movie().
Use it when:
- You want to simplify a complex subsystem.
- You need a single entry point for a large API.
- You want to decouple clients from internal logic.
𝟮. 𝗧𝗵𝗲 𝗙𝗹𝘆𝘄𝗲𝗶𝗴𝗵𝘁 𝗣𝗮𝘁𝘁𝗲𝗿𝗻 Flyweight saves memory. It works when you have thousands of similar objects.
Instead of storing every detail in every object, you split the data. You keep shared, unchanging data (intrinsic state) in one place. You keep unique data (extrinsic state) separate.
Use it when:
- Memory usage is a real problem.
- You manage millions of similar objects, like characters in a text editor or particles in a game.
- You want to use object pooling to improve performance.
𝟯. 𝗧𝗵𝗲 𝗣𝗿𝗼𝘅𝘆 𝗣𝗮𝘁𝘁𝗲𝗿𝗻 Proxy acts as a stand-in for another object. It sits between the client and the real object to control access.
A proxy can:
- Lazy load: Load heavy images only when a user clicks them.
- Control access: Check if a user has permission to delete a database.
- Log activity: Track who uses a specific service.
- Cache results: Return saved data instead of running expensive logic.
Use it when:
- You need to delay expensive operations.
- You must protect a sensitive service.
- You want to add logging or security without changing the original class.
𝗦𝘂𝗺𝗺𝗮𝗿𝘆 𝗧𝗮𝗯𝗹𝗲
• 𝗔𝗱𝗮𝗽𝘁𝗲𝗿: Makes incompatible systems work together. • 𝗕𝗿𝗶𝗱𝗴𝗲: Decouples abstraction from implementation. • 𝗖𝗼𝗺𝗽𝗼𝘀𝗶𝘁𝗲: Builds tree structures. • 𝗗𝗲𝗰𝗼𝗿𝗮𝘁𝗼𝗿: Adds behavior without modifying classes. • 𝗙𝗮𝗰𝗮𝗱𝗲: Simplifies complex subsystems. • 𝗙𝗹𝘆𝘄𝗲𝗶𝗴𝗵𝘁: Shares data to save memory. • 𝗣𝗿𝗼𝘅𝘆: Controls access to objects.
The Golden Rule: Use these patterns to make code maintainable. Do not use them just to show off.
Next, we start the Behavioral Design Patterns series.
Mahdi Shamlou: Pola Desain Struktural 2026 - Facade, Flyweight, Proxy (Contoh Produksi)
Dalam arsitektur perangkat lunak, pola desain struktural berfokus pada bagaimana kelas dan objek digabungkan untuk membentuk struktur yang lebih besar dan efisien. Pola-pola ini membantu mengelola kompleksitas dan memastikan bahwa sistem tetap fleksibel serta mudah dipelihara.
Dalam artikel ini, kita akan membahas tiga pola desain struktural yang sangat penting: Facade, Flyweight, dan Proxy, lengkap dengan contoh penggunaan di dunia nyata (produksi).
1. Facade Pattern
Apa itu Facade?
Pola Facade menyediakan antarmuka (interface) yang disederhanakan untuk sekumpulan antarmuka dalam sebuah subsistem. Bayangkan Anda berurusan dengan sistem yang sangat kompleks dengan banyak kelas yang saling terkait. Tanpa Facade, klien harus memahami setiap detail kelas tersebut untuk melakukan tugas sederhana. Dengan Facade, Anda hanya perlu berinteraksi dengan satu kelas "pintu depan" yang menangani kerumitan di balik layar.
Contoh Produksi: Sistem Smart Home
Bayangkan sebuah sistem Smart Home di mana untuk mengaktifkan "Mode Tidur", Anda harus mematikan lampu, menurunkan suhu AC, mengunci pintu, dan mengaktifkan alarm.
Tanpa Facade, kode Anda akan terlihat seperti ini:
// Kode yang rumit dan berantakan
lightSystem.turnOff();
acSystem.setTemperature(22);
securitySystem.lockDoors();
alarmSystem.arm();
Dengan Facade, kita menyederhanakannya:
class SmartHomeFacade {
constructor(lights, ac, security, alarm) {
this.lights = lights;
this.ac = ac;
this.security = security;
this.alarm = alarm;
}
activateSleepMode() {
console.log("Mengaktifkan Mode Tidur...");
this.lights.turnOff();
this.ac.setTemperature(22);
this.security.lockDoors();
this.alarm.arm();
console.log("Mode Tidur aktif!");
}
}
// Penggunaan di produksi
const smartHome = new SmartHomeFacade(lights, ac, security, alarm);
smartHome.activateSleepMode();
Manfaat:
- Mengurangi ketergantungan (coupling): Klien tidak perlu tahu detail tentang subsistem.
- Kemudahan penggunaan: Menyediakan satu titik masuk yang mudah dipahami.
2. Flyweight Pattern
Apa itu Flyweight?
Pola Flyweight adalah pola struktural yang bertujuan untuk meminimalkan penggunaan memori dengan berbagi data secara efisien di antara banyak objek serupa. Pola ini sangat berguna ketika aplikasi Anda perlu membuat ribuan atau jutaan objek yang memiliki banyak properti yang sama.
Kuncinya adalah memisahkan antara:
- Intrinsic State: Data yang sama untuk semua objek (misalnya, tekstur pohon).
- Extrinsic State: Data yang unik untuk setiap objek (misalnya, koordinat X dan Y pohon).
Contoh Produksi: Mesin Game (Game Engine)
Dalam sebuah game hutan, Anda mungkin memiliki 10.000 pohon. Jika setiap objek pohon menyimpan data tekstur dan model 3D yang berat, memori Anda akan cepat habis.
Dengan Flyweight, kita hanya menyimpan data berat satu kali dan membaginya.
// Flyweight: Menyimpan data yang berat (Intrinsic)
class TreeType {
constructor(name, color, texture) {
this.name = name;
this.color = color;
this.texture = texture; // Data berat
}
}
// Flyweight Factory: Mengelola objek yang dibagikan
class TreeFactory {
constructor() {
this.treeTypes = {};
}
getTreeType(name, color, texture) {
if (!this.treeTypes[name]) {
this.treeTypes[name] = new TreeType(name, color, texture);
}
return this.treeTypes[name];
}
}
// Context: Objek yang menggunakan Flyweight (Extrinsic)
class Tree {
constructor(x, y, treeType) {
this.x = x;
this.y = y;
this.treeType = treeType; // Referensi ke data yang dibagikan
}
draw() {
console.log(`Menanam ${this.treeType.name} di koordinat (${this.x}, ${this.y}) dengan warna ${this.treeType.color}`);
}
}
// Penggunaan di produksi
const factory = new TreeFactory();
const pineType = factory.getTreeType("Pinus", "Hijau Tua", "tekstur_pinus.png");
const trees = [];
for (let i = 0; i < 10000; i++) {
trees.push(new Tree(Math.random() * 100, Math.random() * 100, pineType));
}
Manfaat:
- Efisiensi Memori: Mengurangi penggunaan RAM secara drastis.
- Skalabilitas: Memungkinkan aplikasi menangani jumlah objek yang jauh lebih besar.
3. Proxy Pattern
Apa itu Proxy?
Pola Proxy menyediakan pengganti atau placeholder untuk objek lain untuk mengontrol akses ke objek tersebut. Proxy bertindak sebagai perantara, memungkinkan Anda melakukan sesuatu sebelum atau sesudah permintaan sampai ke objek asli.
Beberapa jenis Proxy yang umum:
- Virtual Proxy: Menunda pembuatan objek yang berat (lazy loading).
- Protection Proxy: Mengontrol hak akses (keamanan).
- Remote Proxy: Mewakili objek yang berada di lokasi berbeda (misalnya, server lain).
- Caching Proxy: Menyimpan hasil dari operasi mahal untuk mempercepat akses berikutnya.
Contoh Produksi: Caching Proxy untuk API
Bayangkan Anda memiliki layanan yang mengambil data profil pengguna dari database yang lambat. Untuk mempercepat aplikasi, Anda bisa menggunakan Proxy untuk menyimpan hasil (cache).
// Interface Objek Asli
class RealDatabase {
fetchUserData(userId) {
console.log(`Mengambil data untuk user ${userId} dari database (proses lambat)...`);
// Simulasi delay database
return { id: userId, name: "Mahdi Shamlou" };
}
}
// Proxy
class DatabaseProxy {
constructor(realDatabase) {
this.realDatabase = realDatabase;
this.cache = {};
}
fetchUserData(userId) {
if (this.cache[userId]) {
console.log(`Mengambil data user ${userId} dari CACHE.`);
return this.cache[userId];
}
const data = this.realDatabase.fetchUserData(userId);
this.cache[userId] = data;
return data;
}
}
// Penggunaan di produksi
const realDb = new RealDatabase();
const proxyDb = new DatabaseProxy(realDb);
console.log(proxyDb.fetchUserData(1)); // Pertama kali: dari database
console.log(proxyDb.fetchUserData(1)); // Kedua kali: dari cache
Manfaat:
- Kontrol Akses: Menambahkan lapisan keamanan atau validasi.
- Optimasi Performa: Mengurangi beban kerja sistem melalui caching atau lazy loading.
- Transparansi: Klien tetap berinteraksi dengan interface yang sama tanpa menyadari adanya perantara.
Kesimpulan
Memahami pola desain struktural adalah kunci untuk membangun sistem yang tangguh.
- Gunakan Facade untuk menyederhanakan antarmuka sistem yang kompleks.
- Gunakan Flyweight untuk mengoptimalkan penggunaan memori pada objek dalam jumlah besar.
- Gunakan Proxy untuk mengontrol akses, menambahkan caching, atau menunda inisialisasi objek.
Dengan menerapkan pola-pola ini, Anda dapat menulis kode yang lebih bersih, lebih cepat, dan lebih mudah dikelola di lingkungan produksi.