Java: Observer Pattern
The Observer Pattern is a behavioral design pattern used in Java to establish a one-to-many dependency between objects. When one object (called the Subject) changes its state, all dependent objects (Observers) are notified and updated automatically.
When to Use Observer Pattern
When changes to one object require notifying and updating multiple dependent objects.
In event-driven architectures or pub-sub systems.
To implement features like notifications, UI updates, or reactive programming.
Basic Observer Pattern Implementation
Define the Observer Interface
package com.agiledcoders.observer;
public interface Observer<T> {
void update(T data);
}
The update
method will receive the updates from the Subject.
Define the Subject Interface
package com.agiledcoders.observer;
public interface Subject<T> {
void register(Observer<T> observer);
void unregister(Observer<T> observer);
void notify(T data);
}
The
register
method allows one to register an Observer.The
unregister
method allows one to unregister an Observer.The notify method notifies the Observer(s)
Implement Subject
package com.agiledcoders.observer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class SubjectImpl implements Subject<String> {
private final List<Observer<String>> observers = new ArrayList<>();
@Override
public void register(Observer<String> observer) {
if (Objects.isNull(observer)) {
throw new IllegalArgumentException("Observer must be non-null");
}
this.observers.add(observer);
}
@Override
public void unregister(Observer<String> observer) {
this.observers.remove(observer);
}
@Override
public void notify(String data) {
this.observers.forEach(stringObserver -> stringObserver.update(data));
}
}
Implement Observer
package com.agiledcoders.observer;
public class ObserverImpl implements Observer<String> {
private static int id;
public ObserverImpl() {
id = id + 1;
}
@Override
public void update(String data) {
System.out.println("----------------------------------------");
System.out.println("Observer Id: " + id + " received update.");
System.out.println(data);
System.out.println("----------------------------------------");
}
}
Create a Runner to test the pattern
package com.agiledcoders.observer;
public class Runner {
public static void main(String[] args) {
Observer<String> first = new ObserverImpl();
Observer<String> second = new ObserverImpl();
Subject<String> subject = new SubjectImpl();
subject.register(first);
subject.register(second);
subject.notify("First iteration");
subject.unregister(first);
subject.notify("Second iteration");
}
}
Output
----------------------------------------
Observer Id: 2 received update.
First iteration
----------------------------------------
----------------------------------------
Observer Id: 2 received update.
First iteration
----------------------------------------
----------------------------------------
Observer Id: 2 received update.
Second iteration
----------------------------------------