On this page
Observer
The Observer pattern defines a one-to-many dependency so that when one object changes state, all dependents are notified automatically.
Problem
Changes to one object require updating multiple dependent objects, and you want loose coupling.
Solution
interface Observer {
void update(String event);
}
class EventPublisher {
private final List<Observer> observers = new ArrayList<>();
void subscribe(Observer observer) {
observers.add(observer);
}
void unsubscribe(Observer observer) {
observers.remove(observer);
}
void publish(String event) {
observers.forEach(o -> o.update(event));
}
}
class EmailNotifier implements Observer {
public void update(String event) {
System.out.println("Email: " + event);
}
}
class SlackNotifier implements Observer {
public void update(String event) {
System.out.println("Slack: " + event);
}
}
// Usage
EventPublisher publisher = new EventPublisher();
publisher.subscribe(new EmailNotifier());
publisher.subscribe(new SlackNotifier());
publisher.publish("Order #123 placed");
Java Built-in Observer (Deprecated)
// java.util.Observable and Observer — deprecated since Java 9
// Do not use in new code
Modern Java Alternatives
PropertyChangeListener
public class Account {
private final PropertyChangeSupport support = new PropertyChangeSupport(this);
private double balance;
void addListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
void setBalance(double balance) {
double old = this.balance;
this.balance = balance;
support.firePropertyChange("balance", old, balance);
}
}
Event Bus (Guava, Spring)
// Spring ApplicationEvent
@Component
class OrderService {
@Autowired ApplicationEventPublisher events;
void placeOrder(Order order) {
// save order...
events.publishEvent(new OrderPlacedEvent(order));
}
}
@Component
class EmailListener {
@EventListener
void onOrderPlaced(OrderPlacedEvent event) {
sendConfirmation(event.getOrder());
}
}
Push vs Pull
- Push — subject sends all data to observers (simple but inflexible)
- Pull — subject notifies, observers query for what they need (more flexible)
When to Use
- State changes in one object require updating others
- Number of dependents is unknown or dynamic
- Loose coupling between subject and observers is desired
Best Practices
- Unsubscribe observers when no longer needed — prevent memory leaks
- Use Spring
@EventListeneror reactive streams for enterprise applications - Keep observer logic decoupled — observers should not modify the subject
- Consider async notification for slow observers