Java Implementation of Observer Pattern for Object Interaction
Observer Pattern Fundamentals
Observer pattern establishes dependency relationships between objects, enabling automatic notifications when one object changes state. The changing object (subject) automatical informs its dependent objects (observers), which then react accordingly. This pattern supports one-to-many relationships where subjects can manage multiple independant observers, allowing dynamic addition and removal for enhanced system extensibility.
The pattern is defined as: "Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically." Common aliases include Publish-Subscribe pattern, Model-View pattern, and Source-Listener pattern.
Pattern Structure
@startuml
abstract Publisher {
+ registerSubscriber(Subscriber s)
+ removeSubscriber(Subscriber s)
+ notifySubscribers()
}
note left of Publisher::notifySubscribers
for(Subscriber sub : subscribers) {
sub.refresh();
}
end note
abstract Subscriber {
+ refresh()
}
class NewsPublisher extends Publisher {
- latestUpdate
+ getUpdate()
+ setUpdate(String update)
}
class EmailSubscriber extends Subscriber {
- currentStatus
+ refresh()
}
note right of EmailSubscriber::refresh
currentStatus = publisher.getUpdate();
end note
Publisher -right-> Subscriber: subscribers
EmailSubscriber -left-> NewsPublisher: publisher
@enduml
Structural Components
- Publisher: Maintains subscriber collection and notification mechanism
- NewsPublisher: Concrete implemantation containing state data
- Subscriber: Interface declaring update method (refresh())
- EmailSubscriber: Concrete implementation tracking publisher state
Java Implementation
import java.util.ArrayList;
import java.util.List;
public class ObserverImplementation {
public static void main(String[] args) {
NewsPublisher publisher = new NewsPublisher();
new EmailSubscriber(publisher);
SMSSubscriber smsSub = new SMSSubscriber(publisher);
publisher.setUpdate("Breaking: System initialized");
publisher.notifySubscribers();
publisher.setUpdate("Update: New features deployed");
publisher.notifySubscribers();
publisher.removeSubscriber(smsSub);
publisher.setUpdate("Final: Service termination notice");
publisher.notifySubscribers();
}
abstract static class Publisher {
protected List<subscriber> subscribers = new ArrayList<>();
public void registerSubscriber(Subscriber s) {
subscribers.add(s);
}
public void removeSubscriber(Subscriber s) {
subscribers.remove(s);
}
public void notifySubscribers() {
for (Subscriber s : subscribers) {
s.refresh();
}
}
}
interface Subscriber {
void refresh();
}
static class NewsPublisher extends Publisher {
private String latestUpdate;
public String getUpdate() {
return latestUpdate;
}
public void setUpdate(String update) {
this.latestUpdate = update;
}
}
static class EmailSubscriber implements Subscriber {
private NewsPublisher publisher;
private String currentStatus;
public EmailSubscriber(NewsPublisher publisher) {
this.publisher = publisher;
publisher.registerSubscriber(this);
}
@Override
public void refresh() {
currentStatus = publisher.getUpdate();
System.out.println("Email Notification: " + currentStatus);
}
}
static class SMSSubscriber implements Subscriber {
private NewsPublisher publisher;
private String currentStatus;
public SMSSubscriber(NewsPublisher publisher) {
this.publisher = publisher;
publisher.registerSubscriber(this);
}
@Override
public void refresh() {
currentStatus = publisher.getUpdate();
System.out.println("SMS Alert: " + currentStatus);
}
}
}
</subscriber>
Output Example
Email Notification: Breaking: System initialized
SMS Alert: Breaking: System initialized
Email Notification: Update: New features deployed
SMS Alert: Update: New features deployed
Email Notification: Final: Service termination notice
Advantages and Limitations
Benefits:
- Decouples presentation layer from business logic
- Establishes abstract publisher-subscriber relationship
- Supports broadcast communication to multiple subscribers
- Extensible without modifying existing code (OCP compliant)
Limitations:
- Notification overhead with numerous subscribers
- Potential circular dependency issues
- No built-in mechanism to convey change causation
Use Cases
- Model-view separation in GUI applications
- Event-driven architectures
- State synchronization across distributed components
- Chained reaction systems (A → B → C)