Observer design pattern
Observer pattern allows to notify clients that state of object was changed. It is mainly used to implement distributed event handling systems, in "event driven" software.
The Observer pattern is also known as Listener, or Publish-Subscribe.
problems
Suppose some data item was downloaded from the internet. And we need to save it in the local database and notify the user about it. If user in a window that shows data items we want update the list. In other cases show message in status bar.
It's a bad idea to implement these tasks in the network manager. The network manager should not depend on the database and graphical interface.
Good idea, if the network manager allows to listen events to anybody. When the window is activated by the user, window can register self as an observer for the network manager and respond correctly to the event. When the user leaves the window, the registration will be canceled.
advantages
- Observers can be added/removed at any point in time without changing code of observable.
- Decouples observable from observers. Observable knows only about observer interface. We can use observable and observers independently of each other.
- Follows the open/closed principle.
- Provides the support for broadcast-type communication.
example
In real life you must take on account the synchronization, and that the gui objects can be touched only in gui thread. For example in Java, if dataItemDownloadListeners is not a concurrent collection you will get exception if addListener and onDataItemDownloaded will be called at same time from different threads.
// just for demo purpose
public class NetworkManager {
// interface for observers of the data item download event
interface DataItemDownloadListener {
void onDataItemDownloaded(DataItem item);
}
// collection of observers
private List<DataItemDownloadListener> dataItemDownloadListeners;
// add observer
public void addListener(DataItemDownloadListener l){
dataItemDownloadListeners.add(l);
}
// remove observer
public void removeListener(DataItemDownloadListener l){
dataItemDownloadListeners.remove(l);
}
// notifies observers about event,
// in our case, that a data item was downloaded
private void onDataItemDownloaded(DataItem item){
for(DataItemDownloadListener l : dataItemDownloadListeners){
l.onDataItemDownloaded(item);
}
}
// ...
}
In the base implementation of the observer pattern, clients explicitly register and unregister. If the client forgot to cancel the registration the application will have a memory leak. This can be prevented by using weak references to the observers: List<WeakReference<DataItemDownloadListener>> dataItemDownloadListeners
You can use set or try remove before adding observer to prevent duplication.
public void addListener(DataItemDownloadListener l){
dataItemDownloadListeners.remove(l);
dataItemDownloadListeners.add(l);
}
Some languages support this pattern directly. For example, Java supports via the Observable class and the Observer interface.