Observer Pattern – notificări reactive între obiecte (event-driven)
În aplicațiile moderne, componentele trebuie să reacționeze rapid la schimbări: o interfață trebuie să se actualizeze când datele se modifică, un serviciu trebuie să trimită notificări, iar un sistem distribuit trebuie să răspundă la evenimente fără dependențe strânse. Observer Pattern rezolvă exact această problemă, permițând notificări reactive între obiecte într-un mod elegant și extensibil.
Observer este unul dintre cele mai folosite pattern-uri comportamentale și stă la baza arhitecturilor event-driven, fiind prezent peste tot în .NET: de la event și delegate, până la IObservable / IObserver.
Ce problemă rezolvă Observer Pattern?
Problema apare atunci când:
-
un obiect (Subject) își schimbă starea;
-
mai multe obiecte (Observers) trebuie să fie informate automat;
-
nu dorim ca Subject-ul să cunoască implementarea concretă a observerilor.
O soluție naivă ar fi să apelăm direct metode pe alte clase, dar acest lucru duce rapid la cuplare strânsă și cod greu de întreținut. Observer Pattern introduce un mecanism standard prin care observatorii se pot abona și dezabona dinamic.
Structura pattern-ului
Observer Pattern implică patru elemente principale:
-
Subject – obiectul observat, care emite notificări;
-
Observer – obiectele interesate de schimbări;
-
Attach / Detach – mecanisme de abonare;
-
Notify – metoda prin care observerii sunt informați.
Exemplu simplu folosind event în C#
În .NET, cea mai comună implementare a Observer Pattern se face folosind event și delegate.
Subject
public class OrderService
{
public event Action<string>? OrderStatusChanged;
public void ProcessOrder()
{
// logica procesării
UpdateStatus("Order processed");
}
private void UpdateStatus(string status)
{
OrderStatusChanged?.Invoke(status);
}
}
Observers
public class EmailNotifier
{
public void OnOrderStatusChanged(string status)
{
Console.WriteLine($"Email sent: {status}");
}
}
public class AuditLogger
{
public void OnOrderStatusChanged(string status)
{
Console.WriteLine($"Audit log: {status}");
}
}
Utilizare
var orderService = new OrderService();
var emailNotifier = new EmailNotifier();
var auditLogger = new AuditLogger();
orderService.OrderStatusChanged += emailNotifier.OnOrderStatusChanged;
orderService.OrderStatusChanged += auditLogger.OnOrderStatusChanged;
orderService.ProcessOrder();
🔹 Avantaj major: OrderService nu știe nimic despre ce fac observerii.
Observer Pattern cu IObservable / IObserver
Pentru scenarii mai avansate, .NET oferă interfețele IObservable<T> și IObserver<T>.
Subject
public class TemperatureSensor : IObservable<int>
{
private readonly List<IObserver<int>> _observers = new();
public IDisposable Subscribe(IObserver<int> observer)
{
_observers.Add(observer);
return new Unsubscriber(_observers, observer);
}
public void SetTemperature(int value)
{
foreach (var observer in _observers)
observer.OnNext(value);
}
}
Observer
public class TemperatureDisplay : IObserver<int>
{
public void OnNext(int value)
{
Console.WriteLine($"Temperature updated: {value}");
}
public void OnCompleted() { }
public void OnError(Exception error) { }
}
Această abordare este foarte potrivită pentru fluxuri continue de date și sisteme reactive.
Când să folosești Observer Pattern?
Observer Pattern este ideal atunci când:
-
ai nevoie de notificări automate;
-
construiești UI-uri reactive;
-
implementezi event sourcing sau domain events;
-
vrei extensibilitate fără a modifica codul existent.
Exemple reale:
-
evenimente din ASP.NET (
EventHandler); -
notificări în aplicații desktop;
-
mesagerie internă între componente;
-
integrare cu sisteme externe.
Avantaje și dezavantaje
✅ Avantaje
-
decuplare între obiecte;
-
extensibilitate mare;
-
suport nativ excelent în .NET.
⚠️ Dezavantaje
-
debugging mai dificil;
-
ordine imprevizibilă a notificărilor;
-
risc de memory leaks dacă nu se face
unsubscribe.
Concluzie
Observer Pattern este una dintre cele mai puternice și utile tehnici din programarea orientată pe obiecte. În .NET, implementarea sa este naturală și elegantă, fie prin event, fie prin IObservable.
Dacă lucrezi cu aplicații reactive, UI-uri sau arhitecturi moderne, acest pattern nu este opțional — este esențial.