Observer design pattern

Observer design pattern

Applikationen drehen sich um Daten und ihre Manipulation. Die Daten in einer Applikation sind das wichtige f├╝r einen Kunden und sollten es auch f├╝r uns als Entwlickler sein. Um es in den Worten von Joe MacMillan von "halt and catch fire" zu sagen:

Software is not the thing, it is the thing that leads us to the thing

Es sollte also nicht ├╝berraschen, dass das heute vorgestellte Design pattern sich um Daten und -austausch dreht.

Jeder, der wei├č wie ein Zeitungsabbonament funktioniert versteht das Observer design pattern berreits.

Don't call us, we'll call you

Das observer design patten erlaubt es Objekten sich auf Zustands├Ąnderungen zu registrieren und ├╝ber diese informiert zu werden. (Hier sei daran erinnert, dass der Zustand eines Objektes als der Wert seiner Attribute zu einer bestimmten Zeit definiert ist).

Ein Prinz wurde geboren

Dieser Artikel w├Ąre kein Artikel ├╝ber design pattern, wenn er kein Tierbeispiel enthalten w├╝rde.

Nehmen wir an, der K├Ânig der Tierwelt wollte alle Tiere ├╝ber ├änderungen in der k├Âniglichen Familie informieren. Als erstes m├╝ssten wir interfaces f├╝r das Observable (den L├Âwen) und Observer (alle anderen Tiere) definieren:

interface Observable {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

interface Observer {
    void update();
}

Die Aufgabe des Observable ist es, die Methode notifyObservers aufzurufen, sobald sich der state des Objektes ge├Ąndert hat. notifyObservers wiederrum ruft die update methode der Observer auf.

Sehen wir uns einmal an, wie der L├Âwe implementiert werden w├╝rde:

class Lion implements Observable {

  /**
   * List of all observers that want to be informed
   */
    private List<Observer> observers = new List<>();

  /**
   * One attribute that defines the state of this lion
   */
    private
List<Lion> children = new List<>();

    @Override
    public void addObserver(Observer observer) {
        this.observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        this.observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : this.observers) {
            observer.update(this);
        }
    }

  /**
   * Whenever a new child is added to the royal family,
   * we also want to notify all of the observers about
   * the change
   */
    public void addChild(Lion child) {
        this.children.add(child);
        this.notifyObservers();
    }
}

Die Sch├Ânheit dieses Design pattern liegt in dem Fakt, dass der L├Âwe keine Informationen ├╝ber die Observer haben muss. F├╝r ihn ist lediglich interessant, dass sie das Observable interface implementieren.

Events: Mehr als Observer

Observer sind an den Zustand / state eines konkreten Objektes gebunden. Events werden h├Ąufig an Stelle von Observern verwendet, da diese es erlauben ├╝ber Dinge zu informieren, die nicht an ein bestimmtes Objekt gebunden sind. In machen F├Ąllen erlauben sie es sogar, Daten zu modifizieren, bevor eine Operation ausgef├╝hrt wird.

Beispiele

JavaScript

JavaScript's EventEmitter ist ein Beispiel f├╝r die St├Ąrken von Events. Diese Events erlauben es ├╝ber bestimmte Aktionen (wie z.b. einen Klick auf einen Button oder neue Date von einem Server) zu warten. Weil Funktionen in JavaSript als Argumente ├╝bergeben werden k├Ânnen, f├╝hlt sich diese Designpattern besonders nat├╝rlich an

// socket.io
var socket = io('http://localhost:3999');
socket.on('data', data => doSomething(data))

Android

In der Android-App Entwicklung werden Observer oft eingesetzt - vorallem f├╝r Nutzerinteraktion. Es existiert keine Weise mit der Android Nutzeroberfl├Ąche zu interagieren, ohne Observer zu nutzen. Interessanterweise besitzt Android nicht ein einzelnes Observer interface, das alle Observer gleich macht, sondern ein interface f├╝r jedes Event / Observable. Dies erlaubt einfachere Fehlersuche und die Verwendung des aktuellen Objektes als Handler f├╝r viele verschiedene Events.

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        setNoiseGenerator(position);
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {}
});

TYPO3

TYPO3 nutzt signal slots, welche JavaScript Events sehr ├Ąhnlich sind (jedoch in einer PHP Umgebung). Diese Signale werden oft vor dem Ausf├╝hren einer Aktion ausgef├╝hrt und erlauben das modifizieren der Daten f├╝r diese Aktion.

ext_localconf.php


/** @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher */
$signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\SignalSlot\Dispatcher');
$signalSlotDispatcher->connect(
    'In2code\Powermail\Domain\Service\SendMailService',
    'sendTemplateEmailBeforeSend',
    'NIMIUS\Testext\Util\DebugUtil',
    'routeMailBack',
    FALSE
);

Classes/Util/DebugUtil.php

namespace NIMIUS\Testext\Util;
use TYPO3\CMS\Core\Mail\MailMessage;

class DebugUtil {

    /**
     * Reroutes all outgoing powermail messages to a test adress
     * @param MailMessage $message
     * @return void
     */
    public routMailBack(MailMessage $message) {
        $message->setTo([ 'testing@nimius.net' => 'NIMIUS Testing' ]);
    }
}

├ťber uns

land in sicht bietet digitale Lo╠łsungen fu╠łr Destinationen und Leistungstra╠łger im Tourismus: toubiz┬«-Infosystem fu╠łr touristische Infrastruktur, Webportale und das Frontend fu╠łr das TOMAS┬« Buchungssystem.

Standort Deutschland

Br├╝hlmatten 16
79295 Sulzburg

Telefon +49 7634 56956-0

Soziale Netzwerke