The observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
It is mainly used for implementing distributed event handling systems, in "event driven" software. In those systems, the subject is usually named a "stream of events" or "stream source of events", while the observers are called "sinks of events". The stream nomenclature alludes to a physical setup where the observers are physically separated and have no control over the emitted events from the subject/stream-source. This pattern then perfectly suits any process where data arrives from some input that is not available to the CPU at startup, but instead arrives "at random" (HTTP requests, GPIO data, user input from keyboard/mouse/..., distributed databases and blockchains, ...). Most modern programming-languages comprise built-in "event" constructs implementing the observer-pattern components. While not mandatory, most 'observers' implementations would use background threads listening for subject-events and other support mechanisms provided by the kernel (Linux epoll, ...).
The Observer design pattern is one of the twenty-three well-known "Gang of Four" design patterns describing how to solve recurring design challenges in order to design flexible and reusable object-oriented software, i.e. objects which are easier to implement, change, test, and reuse.[1]
The Observer pattern addresses the following problems:[2]
Defining a one-to-many dependency between objects by defining one object (subject) that updates the state of dependent objects directly is inflexible because it couples the subject to particular dependent objects. Still, it can make sense from a performance point of view or if the object implementation is tightly coupled (think of low-level kernel structures that execute thousands of times a second). Tightly coupled objects can be hard to implement in some scenarios, and hard to reuse because they refer to and know about (and how to update) many different objects with different interfaces. In other scenarios, tightly coupled objects can be a better option since the compiler will be able to detect errors at compile-time and optimize the code at the CPU instruction level.
Subject
and Observer
objects.The sole responsibility of a subject is to maintain a list of observers and to notify them of state changes by calling their update()
operation. The responsibility of observers is to register (and unregister) themselves on a subject (to get notified of state changes) and to update their state (synchronize their state with the subject's state) when they are notified. This makes subject and observers loosely coupled. Subject and observers have no explicit knowledge of each other. Observers can be added and removed independently at run-time. This notification-registration interaction is also known as publish-subscribe.
See also the UML class and sequence diagram below.
The observer pattern can cause memory leaks, known as the lapsed listener problem, because in a basic implementation, it requires both explicit registration and explicit deregistration, as in the dispose pattern, because the subject holds strong references to the observers, keeping them alive. This can be prevented by the subject holding weak references to the observers.
Typically, the observer pattern is implemented so the "subject" being "observed" is part of the object for which state changes are being observed (and communicated to the observers). This type of implementation is considered "tightly coupled", forcing both the observers and the subject to be aware of each other and have access to their internal parts, creating possible issues of scalability, speed, message recovery and maintenance (also called event or notification loss), the lack of flexibility in conditional dispersion, and possible hindrance to desired security measures. In some (non-polling) implementations of the publish-subscribe pattern (aka the pub-sub pattern), this is solved by creating a dedicated "message queue" server (and sometimes an extra "message handler" object) as an extra stage between the observer and the object being observed, thus decoupling the components. In these cases, the message queue server is accessed by the observers with the observer pattern, "subscribing to certain messages" knowing only about the expected message (or not, in some cases), while knowing nothing about the message sender itself; the sender also may know nothing about the observers. Other implementations of the publish-subscribe pattern, which achieve a similar effect of notification and communication to interested parties, do not use the observer pattern at all.[3][4]
In early implementations of multi-window operating systems like OS/2 and Windows, the terms "publish-subscribe pattern" and "event driven software development" were used as a synonym for the observer pattern.[5]
The observer pattern, as described in the GoF book, is a very basic concept and does not address removing interest in changes to the observed "subject" or special logic to be done by the observed "subject" before or after notifying the observers. The pattern also does not deal with recording when change notifications are sent or guaranteeing that they are being received. These concerns are typically handled in message queueing systems of which the observer pattern is only a small part.
Related patterns: Publish–subscribe pattern, mediator, singleton.
The observer pattern may be used in the absence of publish-subscribe, as in the case where model status is frequently updated. Frequent updates may cause the view to become unresponsive (e.g., by invoking many repaint calls); such observers should instead use a timer. Thus instead of being overloaded by change message, the observer will cause the view to represent the approximate state of the model at a regular interval. This mode of observer is particularly useful for progress bars, where the underlying operation's progress changes with several times per second.
In the above UML class diagram, the Subject
class does not update the state of dependent objects directly.
Instead, Subject
refers to the Observer
interface (update()
) for updating state, which makes the Subject
independent of how the state of dependent objects is updated.
The Observer1
and Observer2
classes implement the Observer
interface by synchronizing their state with subject's state.
The UML sequence diagram
shows the run-time interactions: The Observer1
and Observer2
objects call attach(this)
on Subject1
to register themselves. Assuming that the state of Subject1
changes,
Subject1
calls notify()
on itself.
notify()
calls update()
on
the registered Observer1
and Observer2
objects, which request the changed data (getState()
) from Subject1
to update (synchronize) their state.
While the library classes java.util.Observer and java.util.Observable exist, they have been deprecated in Java 9 because the model implemented was quite limited.
Below is an example written in Java that takes keyboard input and treats each input line as an event. When a string is supplied from System.in, the method notifyObservers
is then called, in order to notify all observers of the event's occurrence, in the form of an invocation of their 'update' methods.
import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;
class EventSource {
public interface Observer {
void update(String event);
}
private final List<Observer> observers = new ArrayList<>();
private void notifyObservers(String event) {
observers.forEach(observer -> observer.update(event));
}
public void addObserver(Observer observer) {
observers.add(observer);
}
public void scanSystemIn() {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
notifyObservers(line);
}
}
}
public class ObserverDemo {
public static void main(String[] args) {
System.out.println("Enter Text: ");
EventSource eventSource = new EventSource();
eventSource.addObserver(event -> {
System.out.println("Received response: " + event);
});
eventSource.scanSystemIn();
}
}
class EventSource {
private observers = []
private notifyObservers(String event) {
observers.each { it(event) }
}
void addObserver(observer) {
observers += observer
}
void scanSystemIn() {
var scanner = new Scanner(System.in)
while (scanner) {
var line = scanner.nextLine()
notifyObservers(line)
}
}
}
println 'Enter Text: '
var eventSource = new EventSource()
eventSource.addObserver { event ->
println "Received response: $event"
}
eventSource.scanSystemIn()
import java.util.Scanner
typealias Observer = (event: String) -> Unit;
class EventSource {
private var observers = mutableListOf<Observer>()
private fun notifyObservers(event: String) {
observers.forEach { it(event) }
}
fun addObserver(observer: Observer) {
observers += observer
}
fun scanSystemIn() {
val scanner = Scanner(System.`in`)
while (scanner.hasNext()) {
val line = scanner.nextLine()
notifyObservers(line)
}
}
}
fun main(arg: List<String>) {
println("Enter Text: ")
val eventSource = EventSource()
eventSource.addObserver { event ->
println("Received response: $event")
}
eventSource.scanSystemIn()
}
uses
System.Generics.Collections
, System.SysUtils
;
type
IObserver = interface
['{0C8F4C5D-1898-4F24-91DA-63F1DD66A692}']
procedure Update(const AValue: string);
end;
type
TEdijsObserverManager = class
strict private
FObservers: TList<IObserver>;
public
constructor Create; overload;
destructor Destroy; override;
procedure NotifyObservers(const AValue: string);
procedure AddObserver(const AObserver: IObserver);
procedure UnregisterObsrver(const AObserver: IObserver);
end;
type
TListener = class(TInterfacedObject, IObserver)
strict private
FName: string;
public
constructor Create(const AName: string); reintroduce;
procedure Update(const AValue: string);
end;
procedure TEdijsObserverManager.AddObserver(const AObserver: IObserver);
begin
if not FObservers.Contains(AObserver) then
FObservers.Add(AObserver);
end;
begin
FreeAndNil(FObservers);
inherited;
end;
procedure TEdijsObserverManager.NotifyObservers(const AValue: string);
var
i: Integer;
begin
for i := 0 to FObservers.Count - 1 do
FObservers[i].Update(AValue);
end;
procedure TEdijsObserverManager.UnregisterObsrver(const AObserver: IObserver);
begin
if FObservers.Contains(AObserver) then
FObservers.Remove(AObserver);
end;
constructor TListener.Create(const AName: string);
begin
inherited Create;
FName := AName;
end;
procedure TListener.Update(const AValue: string);
begin
WriteLn(FName + ' listener received notification: ' + AValue);
end;
procedure TEdijsForm.ObserverExampleButtonClick(Sender: TObject);
var
_DoorNotify: TEdijsObserverManager;
_ListenerHusband: IObserver;
_ListenerWife: IObserver;
begin
_DoorNotify := TEdijsObserverManager.Create;
try
_ListenerHusband := TListener.Create('Husband');
_DoorNotify.AddObserver(_ListenerHusband);
_ListenerWife := TListener.Create('Wife');
_DoorNotify.AddObserver(_ListenerWife);
_DoorNotify.NotifyObservers('Someone is knocking on the door');
finally
FreeAndNil(_DoorNotify);
end;
end;
Output
Husband listener received notification: Someone is knocking on the door Wife listener received notification: Someone is knocking on the door
A similar example in Python:
class Observable:
def __init__(self):
self._observers = []
def register_observer(self, observer):
self._observers.append(observer)
def notify_observers(self, *args, **kwargs):
for obs in self._observers:
obs.notify(self, *args, **kwargs)
class Observer:
def __init__(self, observable):
observable.register_observer(self)
def notify(self, observable, *args, **kwargs):
print("Got", args, kwargs, "From", observable)
subject = Observable()
observer = Observer(subject)
subject.notify_observers("test", kw="python")
# prints: Got ('test',) {'kw': 'python'} From <__main__.Observable object at 0x0000019757826FD0>
public class Payload
{
public string Message { get; set; }
}
public class Subject : IObservable<Payload>
{
public IList<IObserver<Payload>> Observers { get; set; }
public Subject()
{
Observers = new List<IObserver<Payload>>();
}
public IDisposable Subscribe(IObserver<Payload> observer)
{
if (!Observers.Contains(observer))
{
Observers.Add(observer);
}
return new Unsubscriber(Observers, observer);
}
public void SendMessage(string message)
{
foreach (var observer in Observers)
{
observer.OnNext(new Payload { Message = message });
}
}
}
public class Unsubscriber : IDisposable
{
private IObserver<Payload> observer;
private IList<IObserver<Payload>> observers;
public Unsubscriber(IList<IObserver<Payload>> observers, IObserver<Payload> observer)
{
this.observers = observers;
this.observer = observer;
}
public void Dispose()
{
if (observer != null && observers.Contains(observer))
{
observers.Remove(observer);
}
}
}
public class Observer : IObserver<Payload>
{
public string Message { get; set; }
public void OnCompleted()
{
}
public void OnError(Exception error)
{
}
public void OnNext(Payload value)
{
Message = value.Message;
}
public IDisposable Register(Subject subject)
{
return subject.Subscribe(this);
}
}
Javascript has a deprecated Object.observe
function that was a more accurate implementation of the Observer pattern.[7] This would fire events upon change to the observed object. Without the deprecated Object.observe
function, a programmer can still implement the pattern with more explicit code:[8]
var Subject = {
_state: 0,
_observers: [],
add: function(observer) {
this._observers.push(observer);
},
getState: function() {
return this._state;
},
setState: function(value) {
this._state = value;
for (var i = 0; i < this._observers.length; i++)
{
this._observers[i].signal(this);
}
}
};
var Observer = {
signal: function(subject) {
var currentValue = subject.getState();
console.log(currentValue);
}
}
Subject.add(Observer);
Subject.setState(10);
//Output in console.log - 10
By: Wikipedia.org
Edited: 2021-06-18 19:29:19
Source: Wikipedia.org