Apa itu Observer Pattern? Penjelasan Lengkap untuk Pemula
Pendahuluan
Pernahkah kamu berlangganan newsletter atau menekan tombol Subscribe di YouTube? Setiap kali channel tersebut mengunggah video baru, kamu otomatis mendapat notifikasi — tanpa perlu terus-menerus membuka YouTube untuk mengeceknya secara manual.
Itulah inti dari Observer Pattern: sebuah pola desain di mana satu objek (disebut Subject atau Publisher) memberi tahu banyak objek lain (disebut Observer atau Subscriber) secara otomatis ketika ada perubahan state.
Observer Pattern adalah salah satu dari 23 pola desain klasik yang dikategorikan sebagai behavioral pattern — artinya ia mengatur cara objek-objek berkomunikasi satu sama lain. Jika kamu sudah familiar dengan konsep OOP, memahami pola ini akan terasa lebih mudah. Kamu bisa membaca dulu artikel OOP di Python: Class, Object, dan Inheritance sebagai fondasi sebelum melanjutkan.
Memahami Konsep Observer Pattern
Analogi Sehari-hari
Bayangkan kamu membaca koran. Ada tiga cara kamu bisa mendapatkan koran:
-
Cara manual (tanpa Observer Pattern): Setiap pagi kamu pergi ke warung, cek apakah koran baru sudah datang atau belum. Jika belum, kamu pulang dan coba lagi besok.
-
Cara Observer Pattern: Kamu berlangganan ke agen koran. Setiap kali koran baru terbit, agen langsung mengantar ke rumahmu. Kamu tidak perlu melakukan apa-apa — cukup tunggu notifikasi.
Cara kedua jauh lebih efisien! Observer Pattern bekerja persis seperti sistem berlangganan ini.
Kapan Menggunakannya?
Observer Pattern sangat berguna ketika:
- Satu objek berubah dan perlu memperbarui banyak objek lain secara otomatis
- Kamu tidak tahu berapa banyak objek yang perlu diperbarui saat runtime
- Kamu ingin mengurangi coupling (ketergantungan langsung) antar objek
Bayangkan kamu membangun aplikasi seperti Tokopedia: ketika harga produk berubah, sistem harus memberi tahu notifikasi pengguna, memperbarui tampilan harga di berbagai halaman, dan mencatat log perubahan — semuanya secara bersamaan. Observer Pattern adalah solusinya.
Komponen Utama dalam Observer Pattern
Observer Pattern terdiri dari tiga komponen utama:
1. Subject (Publisher)
Objek yang “diamati”. Ia menyimpan daftar Observer yang terdaftar dan memberi tahu mereka ketika state-nya berubah.
Tanggung jawab Subject:
- Menyimpan daftar Observer (
attach) - Menghapus Observer dari daftar (
detach) - Memberi tahu semua Observer saat ada perubahan (
notify)
2. Observer (Subscriber)
Objek yang “mengamati” Subject. Setiap Observer mendefinisikan cara mereka bereaksi ketika menerima notifikasi (update). Observer tidak tahu detail tentang Subject — mereka hanya menunggu notifikasi dan bereaksi sesuai kebutuhan masing-masing.
3. Concrete Implementations
Ini adalah implementasi nyata dari Subject dan Observer yang disesuaikan dengan kebutuhan spesifik aplikasi.
Concrete Subject adalah kelas yang menurunkan Subject dan menambahkan logika bisnis nyata. Ia memiliki state yang bisa berubah (misalnya harga produk, status pesanan, posisi GPS) dan memanggil notify() setiap kali state tersebut berubah.
Concrete Observer adalah kelas yang menurunkan Observer dan mendefinisikan reaksi spesifik. Setiap Concrete Observer bisa bereaksi berbeda terhadap notifikasi yang sama — misalnya satu Observer mengirim email, Observer lain menampilkan pop-up, dan Observer ketiga mencatat ke log.
Hubungan antara ketiganya bisa digambarkan seperti ini:
Subject (interface) Observer (interface)
| |
v v
ConcreteSubject ----notify---> ConcreteObserverA
(Product) ConcreteObserverB
ConcreteObserverC
Kunci utamanya: Subject hanya tahu bahwa Observer memiliki metode update() — ia tidak peduli siapa mereka atau apa yang mereka lakukan. Inilah yang membuat kode menjadi loosely coupled.
Implementasi Sederhana dalam Kode
Implementasi di Python
Mari kita buat sistem notifikasi harga produk sederhana yang bisa langsung dijalankan:
from abc import ABC, abstractmethod
from typing import List
# Interface untuk Observer
class Observer(ABC):
@abstractmethod
def update(self, product_name: str, new_price: float) -> None:
pass
# Interface untuk Subject
class Subject(ABC):
@abstractmethod
def attach(self, observer: Observer) -> None:
pass
@abstractmethod
def detach(self, observer: Observer) -> None:
pass
@abstractmethod
def notify(self) -> None:
pass
# Concrete Subject: Produk dengan harga yang bisa berubah
class Product(Subject):
def __init__(self, name: str, price: float):
self._name = name
self._price = price
self._observers: List[Observer] = []
def attach(self, observer: Observer) -> None:
self._observers.append(observer)
print(f"✅ Observer '{observer.__class__.__name__}' terdaftar ke produk '{self._name}'")
def detach(self, observer: Observer) -> None:
self._observers.remove(observer)
print(f"❌ Observer '{observer.__class__.__name__}' dihapus dari produk '{self._name}'")
def notify(self) -> None:
for observer in self._observers:
observer.update(self._name, self._price)
def set_price(self, new_price: float) -> None:
print(f"\n📦 Harga '{self._name}' berubah: Rp{self._price:,.0f} → Rp{new_price:,.0f}")
self._price = new_price
self.notify()
# Concrete Observer 1: Notifikasi Email
class EmailNotifier(Observer):
def update(self, product_name: str, new_price: float) -> None:
print(f"📧 Email dikirim: Harga '{product_name}' sekarang Rp{new_price:,.0f}")
# Concrete Observer 2: Notifikasi Push
class PushNotifier(Observer):
def update(self, product_name: str, new_price: float) -> None:
print(f"🔔 Push notification: '{product_name}' turun ke Rp{new_price:,.0f}!")
# Concrete Observer 3: Logger
class PriceLogger(Observer):
def update(self, product_name: str, new_price: float) -> None:
print(f"📝 Log dicatat: {product_name} = Rp{new_price:,.0f}")
# --- Penggunaan ---
if __name__ == "__main__":
laptop = Product("Laptop Gaming", 15_000_000)
email_notifier = EmailNotifier()
push_notifier = PushNotifier()
logger = PriceLogger()
laptop.attach(email_notifier)
laptop.attach(push_notifier)
laptop.attach(logger)
laptop.set_price(13_500_000)
laptop.set_price(12_000_000)
laptop.detach(push_notifier)
laptop.set_price(11_000_000)
Output:
✅ Observer 'EmailNotifier' terdaftar ke produk 'Laptop Gaming'
✅ Observer 'PushNotifier' terdaftar ke produk 'Laptop Gaming'
✅ Observer 'PriceLogger' terdaftar ke produk 'Laptop Gaming'
📦 Harga 'Laptop Gaming' berubah: Rp15.000.000 → Rp13.500.000
📧 Email dikirim: Harga 'Laptop Gaming' sekarang Rp13.500.000
🔔 Push notification: 'Laptop Gaming' turun ke Rp13.500.000!
📝 Log dicatat: Laptop Gaming = Rp13.500.000
📦 Harga 'Laptop Gaming' berubah: Rp13.500.000 → Rp12.000.000
📧 Email dikirim: Harga 'Laptop Gaming' sekarang Rp12.000.000
🔔 Push notification: 'Laptop Gaming' turun ke Rp12.000.000!
📝 Log dicatat: Laptop Gaming = Rp12.000.000
❌ Observer 'PushNotifier' dihapus dari produk 'Laptop Gaming'
📦 Harga 'Laptop Gaming' berubah: Rp12.000.000 → Rp11.000.000
📧 Email dikirim: Harga 'Laptop Gaming' sekarang Rp11.000.000
📝 Log dicatat: Laptop Gaming = Rp11.000.000
Perhatikan bagaimana pada perubahan harga ketiga, PushNotifier tidak lagi menerima notifikasi karena sudah di-detach. Inilah fleksibilitas Observer Pattern.
Implementasi di JavaScript
Di JavaScript, Observer Pattern sering digunakan untuk mengelola event. Berikut contoh implementasi lengkap menggunakan class modern:
class EventEmitter {
constructor() {
this.listeners = {};
}
on(event, callback) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(callback);
return this;
}
off(event, callback) {
if (this.listeners[event]) {
this.listeners[event] = this.listeners[event].filter(
(listener) => listener !== callback
);
}
return this;
}
emit(event, data) {
if (this.listeners[event]) {
this.listeners[event].forEach((callback) => callback(data));
}
return this;
}
}
// Penggunaan: Sistem notifikasi stok produk
const stockManager = new EventEmitter();
const updateUI = (data) => {
console.log(`🖥️ UI diperbarui: ${data.product} tersisa ${data.stock} unit`);
};
const alertAdmin = (data) => {
if (data.stock < 5) {
console.log(`🚨 Alert Admin: Stok ${data.product} hampir habis! (${data.stock} unit)`);
}
};
const logToDatabase = (data) => {
const timestamp = new Date().toISOString().slice(0, 19);
console.log(`💾 DB Log: [${timestamp}] ${data.product} = ${data.stock} unit`);
};
stockManager.on("stockUpdate", updateUI);
stockManager.on("stockUpdate", alertAdmin);
stockManager.on("stockUpdate", logToDatabase);
console.log("=== Update stok Sepatu Nike ===");
stockManager.emit("stockUpdate", { product: "Sepatu Nike", stock: 3 });
console.log("\n=== Update stok Kaos Polos ===");
stockManager.emit("stockUpdate", { product: "Kaos Polos", stock: 20 });
stockManager.off("stockUpdate", alertAdmin);
console.log("\n=== Update stok Tas Kulit (tanpa alert admin) ===");
stockManager.emit("stockUpdate", { product: "Tas Kulit", stock: 2 });
Output:
=== Update stok Sepatu Nike ===
🖥️ UI diperbarui: Sepatu Nike tersisa 3 unit
🚨 Alert Admin: Stok Sepatu Nike hampir habis! (3 unit)
💾 DB Log: [2026-04-10T06:00:00] Sepatu Nike = 3 unit
=== Update stok Kaos Polos ===
🖥️ UI diperbarui: Kaos Polos tersisa 20 unit
💾 DB Log: [2026-04-10T06:00:00] Kaos Polos = 20 unit
=== Update stok Tas Kulit (tanpa alert admin) ===
🖥️ UI diperbarui: Tas Kulit tersisa 2 unit
💾 DB Log: [2026-04-10T06:00:00] Tas Kulit = 2 unit
Contoh Kasus Nyata
1. Event Listener di Browser
Ini adalah Observer Pattern yang paling sering kamu gunakan tanpa sadar! Setiap kali kamu menulis addEventListener, kamu sedang mendaftarkan sebuah Observer:
const tombol = document.getElementById("beli-sekarang");
// Mendaftarkan observer untuk event "click"
tombol.addEventListener("click", () => {
console.log("Produk ditambahkan ke keranjang!");
});
tombol.addEventListener("click", () => {
console.log("Analitik: pengguna klik tombol beli");
});
// Saat tombol diklik, KEDUA fungsi dipanggil otomatis
Saat tombol diklik, semua fungsi yang terdaftar akan dipanggil secara otomatis. Untuk memahami lebih dalam cara kerja DOM dan event di browser, baca artikel Belajar Manipulasi DOM JavaScript untuk Pemula.
2. Sistem Notifikasi Real-Time
Jika kamu ingin membangun layanan seperti Gojek — di mana driver, penumpang, dan sistem backend harus saling mendapat update posisi secara real-time — Observer Pattern adalah fondasi arsitekturnya.
class RideSubject:
"""Concrete Subject: Status perjalanan ojek online"""
def __init__(self):
self._status = "mencari_driver"
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def notify(self):
for observer in self._observers:
observer.update(self._status)
def update_status(self, new_status):
self._status = new_status
print(f"\n[STATUS] Perjalanan: {self._status}")
self.notify()
class PassengerApp:
"""Concrete Observer: Aplikasi penumpang"""
def update(self, status):
messages = {
"driver_ditemukan": "Driver ditemukan! Sedang menuju lokasimu.",
"driver_tiba": "Driver sudah tiba di lokasi penjemputan!",
"perjalanan_dimulai": "Perjalanan dimulai. Selamat jalan!",
"selesai": "Perjalanan selesai. Terima kasih!"
}
print(f"📱 Penumpang: {messages.get(status, status)}")
class DriverApp:
"""Concrete Observer: Aplikasi driver"""
def update(self, status):
if status == "driver_ditemukan":
print(f"🏍️ Driver: Navigasi ke lokasi penumpang dimulai.")
elif status == "selesai":
print(f"🏍️ Driver: Perjalanan selesai, menunggu order berikutnya.")
class AdminDashboard:
"""Concrete Observer: Dashboard admin"""
def update(self, status):
print(f"📊 Dashboard: Status diperbarui → {status}")
if __name__ == "__main__":
perjalanan = RideSubject()
perjalanan.attach(PassengerApp())
perjalanan.attach(DriverApp())
perjalanan.attach(AdminDashboard())
perjalanan.update_status("driver_ditemukan")
perjalanan.update_status("driver_tiba")
perjalanan.update_status("perjalanan_dimulai")
perjalanan.update_status("selesai")
Output:
[STATUS] Perjalanan: driver_ditemukan
📱 Penumpang: Driver ditemukan! Sedang menuju lokasimu.
🏍️ Driver: Navigasi ke lokasi penumpang dimulai.
📊 Dashboard: Status diperbarui → driver_ditemukan
[STATUS] Perjalanan: driver_tiba
📱 Penumpang: Driver sudah tiba di lokasi penjemputan!
📊 Dashboard: Status diperbarui → driver_tiba
[STATUS] Perjalanan: perjalanan_dimulai
📱 Penumpang: Perjalanan dimulai. Selamat jalan!
📊 Dashboard: Status diperbarui → perjalanan_dimulai
[STATUS] Perjalanan: selesai
📱 Penumpang: Perjalanan selesai. Terima kasih!
🏍️ Driver: Perjalanan selesai, menunggu order berikutnya.
📊 Dashboard: Status diperbarui → selesai
Pertanyaan yang Sering Diajukan
Apa perbedaan Observer Pattern dengan Strategy Pattern?
Strategy Pattern berfokus pada cara melakukan sesuatu — kamu mengganti algoritma atau perilaku sebuah objek secara dinamis. Observer Pattern berfokus pada komunikasi antar objek — satu objek memberi tahu banyak objek lain saat terjadi perubahan. Strategy berurusan dengan “bagaimana”, Observer berurusan dengan “kapan dan siapa yang perlu tahu”. Keduanya adalah pola behavioral, tapi memiliki tujuan yang berbeda.
Apakah Observer Pattern dan Event Listener itu sama?
Event Listener di browser adalah implementasi konkret dari Observer Pattern. Konsep dasarnya sama: ada publisher (elemen DOM) dan subscriber (fungsi callback). Jadi Observer Pattern adalah pola desain abstrak, sedangkan Event Listener adalah salah satu wujud nyatanya dalam ekosistem JavaScript.
Bagaimana cara menghindari memory leak di Observer Pattern?
Memory leak bisa terjadi jika Observer yang sudah tidak dipakai tidak di-detach dari Subject. Selalu pastikan kamu memanggil detach() atau removeEventListener() saat Observer tidak lagi dibutuhkan — misalnya saat komponen UI dihapus dari halaman. Di JavaScript modern, kamu juga bisa menggunakan AbortController untuk membatalkan listener secara otomatis.
Apakah Observer Pattern cocok untuk semua kasus?
Tidak selalu. Observer Pattern bisa membuat alur program sulit dilacak jika ada terlalu banyak Observer yang saling bergantung. Gunakan pola ini ketika kamu jelas membutuhkan mekanisme one-to-many notification. Untuk hubungan yang lebih sederhana antar dua objek, komunikasi langsung lebih mudah dimengerti dan di-debug.
Apa Design Pattern lain yang perlu dipelajari setelah Observer?
Setelah Observer Pattern, kamu bisa lanjut mempelajari pola behavioral lain seperti Strategy Pattern di artikel Apa itu Strategy Pattern? Penjelasan Lengkap untuk Pemula, atau pola struktural seperti Adapter Pattern. Keduanya sering dikombinasikan dengan Observer dalam sistem yang lebih kompleks.
Kesimpulan
Observer Pattern adalah pola desain yang elegan untuk membangun sistem komunikasi one-to-many antar objek. Dengan memisahkan Subject dari Observer, kode kamu menjadi lebih modular, mudah dikembangkan, dan minim ketergantungan langsung antar komponen.
Ringkasan poin penting:
- Subject menyimpan daftar Observer dan memberi tahu mereka saat state berubah
- Observer mendefinisikan reaksi masing-masing saat menerima notifikasi
- Concrete Implementations adalah wujud nyata dari Subject dan Observer yang disesuaikan dengan kebutuhan bisnis
- Pola ini digunakan di mana-mana: event listener browser, sistem notifikasi, reactive programming, hingga arsitektur microservices
- Selalu
detachObserver yang tidak lagi dibutuhkan untuk menghindari memory leak
Selamat belajar dan terus bereksperimen dengan kode! Design pattern seperti Observer adalah investasi jangka panjang yang akan membuat arsitektur proyekmu jauh lebih rapi — jangan ragu untuk mengeksplorasi artikel-artikel lain di KamusNgoding untuk memperdalam pemahamanmu.