Observer (design pattern)

from Wikipedia, the free encyclopedia

The Observer pattern ( english pattern observer , and listener pattern ) is a design pattern in the field of software development . It belongs to the category of behavioral patterns (English behavioral patterns ) and transfer functions changes to a property to dependent of this object structures. The pattern is one of the so-called GoF patterns ( Gang of Four , see Gang of Four ).

In addition to publish-subscribe ( pub / sub for short ), the observer pattern experiences a further development with the signal slot concept .

use

General application situations

In general, observer patterns are used when an abstraction has several aspects that depend on another aspect of the same abstraction, where a change in one object results in changes in other objects, or where an object should notify other objects without knowing them in detail.

Application example

One or more components graphically represent the state of an object. You know the entire interface of this object. If the state of the object changes, the displaying components must be informed. On the other hand, the object should remain independent of the components, i.e. not know their interface.

Example: Measurement results are shown simultaneously in a bar chart, a line chart and a table. Measured values ​​change permanently. The components of the diagrams should show these changes permanently, but the measured object should not have any knowledge of the structure of these components.

solution

The observed object provides a mechanism for logging on and off observers and informing them of changes. It only knows all of its observers through the (manageable) interface Beobachter. Changes are exchanged completely unspecifically between the observed object and each registered observer. This does not need to know the further structure of these components. The observers in turn implement a (specific) method to react to the change.

There are three different ways to implement the observer pattern:

Push notification
Every time the observed object changes, all observers are notified. However, no data is sent, which is why this form always has the same observer interface. The observers must collect data after the message arrives.
Push update notification
Every time the observed object changes, all observers are notified. In addition, the observed object forwards the update data describing the changes to the observers.
Pull notification
The observer asks independently about the condition of the observed object.

UML diagram

Class diagram showing the roles involved in the design pattern.

The following class diagram shows the roles involved in the design pattern. The subject can have several observers who can belong to different concrete classes.

actors

An Subjekt(observable object, in English publisher , also called "publisher") has a list of observers without knowing their specific types. It offers an interface for logging in and out of observers and an interface for notifying observers of changes.

A concrete subject (concrete, observable object) saves the relevant state and notifies all observers of changes in the state via their update interface. It has an interface for querying the current status.

The Beobachter(also called subscriber in English ) define an update interface.

Concrete observers manage the reference to a concrete subject, whose state they observe and store and whose state is consistent. You implement an update interface using the query interface of the concrete subject.

advantages

Subjects and observers can be varied independently. Subject and observer are loosely coupled in an abstract and minimal way. The observed object does not need to have any knowledge of the structure of its observer, but only knows it via the observer interface. A dependent object receives the changes automatically. Multicasts are also supported.

disadvantage

Changes to the subject lead to high change costs if there are a large number of observers. In addition, the subject informs each observer even if the observer does not need the change information. In addition, the changes can result in further changes and thus require an unexpectedly high level of effort.

The mechanism does not provide any information about what has changed. The resulting independence of the components can, however, also turn out to be an advantage.

Gets an observer during the processing of a reported change in turn changing methods of the subject on, it can result in repeated.

Typically, it cannot be seen in the source code of the subject which observers are being informed exactly. This often makes it difficult to understand which states the program goes through as a whole during an event.

Example in C ++

#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>

class AbstrakterBeobachter {
public:
    virtual void aktualisieren(int) = 0;
};

class Anton: public AbstrakterBeobachter {
public:
    void aktualisieren(int wert) {
        std::cout << "Dies ist Beobachter Anton mit dem Wert " << wert
                  << std::endl;
    }
};

class Berta: public AbstrakterBeobachter {
public:
    void aktualisieren(int wert) {
        std::cout << "Dies ist Beobachter Berta mit dem Wert " << wert
                  << std::endl;
    }
};

class AbstraktesSubjekt {
public:
    virtual void registrieren(const std::shared_ptr<AbstrakterBeobachter>&) {}
    virtual void entfernen(const std::shared_ptr<AbstrakterBeobachter>&) {}
    virtual void benachrichtigen() {}
    virtual void setzeWert(int) {}
};

class Subjekt: public AbstraktesSubjekt {
    std::vector<std::shared_ptr<AbstrakterBeobachter>> _beobachter;
    int _wert = 0;

public:
    void registrieren(const std::shared_ptr<AbstrakterBeobachter>& beobachter) {
        _beobachter.push_back(beobachter);
    }

    void entfernen(const std::shared_ptr<AbstrakterBeobachter>& beobachter) {
        _beobachter.erase(std::remove_if(_beobachter.begin(), _beobachter.end(),
            [&](const std::shared_ptr<AbstrakterBeobachter>& vergleich) {
                return vergleich == beobachter;
            }));
    }

    void benachrichtigen() {
        for (auto& b: _beobachter)
            b->aktualisieren(_wert);
    }

    void setzeWert(int wert) {
        _wert = wert;
        benachrichtigen();
    }
};

int main() {
    std::shared_ptr<AbstraktesSubjekt> subjekt = std::make_shared<Subjekt>();
    std::shared_ptr<AbstrakterBeobachter> anton = std::make_shared<Anton>();
    std::shared_ptr<AbstrakterBeobachter> berta = std::make_shared<Berta>();

    subjekt->registrieren(anton);
    subjekt->registrieren(berta);

    subjekt->setzeWert(1);
    subjekt->entfernen(anton);
    subjekt->setzeWert(2);
    subjekt->entfernen(berta);

    return 0;
}

Output:

Dies ist Beobachter Anton mit dem Wert 1
Dies ist Beobachter Berta mit dem Wert 1
Dies ist Beobachter Berta mit dem Wert 2

Others

During the observation of an object state that has just been carried out, it may be necessary to guarantee a consistent subject state. This can be ensured by synchronous calls to the observer's notification method. (In a multithreading system, synchronization mechanisms such as locks or queues for notifying observers may be required.)

Some programming languages ​​(such as Java ) offer a standard implementation for the observer pattern. However, in a programming language that does not support multiple inheritance of classes, such an implementation means that the subject cannot inherit any further classes, since it already inherits the implementation of the observer pattern.

Related design patterns

A mediator can mediate between subjects and observers.

Web links

Wikibooks: Pattern: Observer  - Learning and teaching materials

Individual evidence

  1. Erich Gamma , Richard Helm , Ralph Johnson , John Vlissides : Design pattern . 5th edition. Addison-Wesley, 1996, ISBN 3-8273-1862-9 , pp. 287 .
  2. Bernd Brügge, Allen H. Dutoit: Object-oriented software technology: with UML, design patterns and Java . 2nd, revised edition. Addison-Wesley Verlag, 2004, ISBN 3-8273-7082-5 .
  3. ^ Observer Interface Javadoc . docs.oracle.com, accessed June 3, 2015