~Java4Beginners~
~Java4Beginners~

Observer

Dieses Pattern wird hergenommen für die 2 Akteuere Subjekt und Beobachter. Ohne Oberserverpattern wäre der Weg zur Informationsgewinnung, dass jeder Beobachter beim Subjekt anfrägt, ob es irgendwelche Änderungen gegeben hat. Um diese Abfrageflut zu vermeiden, setzt das Observerpattern auf die Grundidee auf, dass das Subjekt den Bobachtern mitteilt, dass eine Änderung eingetreten ist.

Beobachter, die benachrichtigt werden möchten, müssen sich beim Subjekt anmelden. Subjekt verwaltet die Beobachter in einer Liste.

UML-Darstellung



Klasse Subjekt

Diese Klasse gestalten wir als Interface mit den abstrakten Methoden addBeobachter(), removeBeobachter() und benachrichtigeBeobachter(). Damit sorgen wir, dass jedes Subjekt zwangsweise über diese 3 Methoden verfügen muss.

package designpatternobserver;

/**
 * Beispiel des Beobachtermusters
 * @author Markus Badzura
 */
public interface Subjekt {
	public abstract void addBeobachter(Beobachter beobachter);
	public abstract void removeBeobachter(Beobachter beobachter);
	public abstract void benachrichtigeBeobachter();
}

Klasse Beobachter

Auch die Beobachterklasse wird als Interface mit einer abstrakten Methote update() erstellt.

package designpatternobserver;

/**
 * Beispiel des Beobachtermusters
 * @author Markus Badzura
 */
public interface Beobachter {
	public abstract void update();
}

Klasse KonkretesSubjekt

Diese Klasse benutzt das Interface Subjekt. Des weiteren benötigen wir eine List, in welcher wir die Beobachter hinzufügen und entfernen können.

Ausserdem implementieren wir die Setter- und Getter-Methode für den Status.

package designpatternobserver;

import java.util.ArrayList;
import java.util.List;

/**
 * Beispiel des Beobachtermusters
 * @author Markus Badzura
 */
public class KonkretesSubjekt implements Subjekt {
        // Liste für angemeldete Beobachter 
	List beobachterList = new ArrayList<>();
        //Status-Variable
	int status = 0;
 
        /**
         * Beobachter zur Liste hinzufügen
         * @param beobachter 
         */
	@Override
	public void addBeobachter(Beobachter beobachter) {
		this.beobachterList.add(beobachter);
	}
        
        /**
         * Beobachter aus Liste entfernen
         * @param beobachter 
         */
	@Override
	public void removeBeobachter(Beobachter beobachter) {
		this.beobachterList.remove(beobachter);
	}
 
        /**
         * Alle Beobachter des konkretenSubjektes benachrichtigen
         */
	@Override
	public void benachrichtigeBeobachter() {
            beobachterList.forEach((beobachter) -> {beobachter.update();
            });
	}
 
        /**
         * Rückgabe Statuswert
         * @return status
         */
	public int getStatus() {
		return status;
	}
        
        /**
         * Statuswert setzen
         * @param status 
         */
	public void setStatus(int status) {
		this.status = status;
		this.benachrichtigeBeobachter();
	}
}
Es können beliebig viele Klassen mit dem Interface von Subjekt erstellt werden, ebenso wie von den nun folgenden Konkreten Beobachtern (Dort hab ich 2 konkrete Beobachter erstellt).

Klasse KonkreterBeobachter und KonkreterBeobachter1

Die beiden Klassen verwenden als Interface die Klasse Beobachter und implementieren somit die Methode update(). Im Konstruktor wird festgelegt, auf welches konkreteSubjekt sich der konkreteBeobachter anmeldet.

package designpatternobserver;

/**
 * Beispiel des Beobachtermusters
 * @author Markus Badzura
 */ 
public class KonkreterBeobachter implements Beobachter {
 
	private KonkretesSubjekt konkretesSubjekt;
 
        /**
         * Anmelden am Subjekt
         * @param konkretesSubjekt 
         */
        @SuppressWarnings("LeakingThisInConstructor")
	public KonkreterBeobachter(KonkretesSubjekt konkretesSubjekt) {
		this.konkretesSubjekt = konkretesSubjekt;
		this.konkretesSubjekt.addBeobachter(this);
	}
 
        /**
         * Abfrage des des Statuswertes nach Benachrichtigung
         */
	@Override
	public void update() {
		int newState = konkretesSubjekt.getStatus();
		System.out.println("Konkreter Beobachter - State: "+newState);
	} 
}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

package designpatternobserver;

/**
 * Beispiel des Beobachtermusters
 * @author Markus Badzura
 */
public class KonkreterBeobachter1 implements Beobachter {
 
	private KonkretesSubjekt konkretesSubjekt;
        
        /**
         * Anmelden am Subjekt
         * @param konkretesSubjekt 
         */
        @SuppressWarnings("LeakingThisInConstructor")
	public KonkreterBeobachter1(KonkretesSubjekt konkretesSubjekt) {
		this.konkretesSubjekt = konkretesSubjekt;
 
		// Durchführung der Registrierung beim übergebenen Subjekt
		this.konkretesSubjekt.addBeobachter(this);
	}
 
        /**
         * Abfrage des des Statuswertes nach Benachrichtigung
         */        
	@Override
	public void update() {
		int newState = konkretesSubjekt.getStatus();
		System.out.println("KonkreterBeobachter1" + " - State: "+newState);
	} 
}

Klasse Client

Wir brauchen nun auch noch eine Startklasse, damit wir die Auswirkung unseres Entwurfsmusters sehen können.

package designpatternobserver;

/**
 * Beispiel des Beobachtermusters
 * @author Markus Badzura
 */
public class Client {
 
	public static void main(String[] args) {
 
		// Erzeugung der Subjekte
		KonkretesSubjekt konkretesSubjekt = new KonkretesSubjekt();
                KonkretesSubjekt konkretesSubjekt1 = new KonkretesSubjekt();
 
		// Erzeugung des Beobachters. Dabei wird
		// das jeweilige Subjekt übergeben und registriert.
		KonkreterBeobachter konkreterBeobachter = 
                        new KonkreterBeobachter(konkretesSubjekt);
                KonkreterBeobachter konkreterBeobachter1 = 
                        new KonkreterBeobachter(konkretesSubjekt1);
                KonkreterBeobachter1 konkreterBeobachter2 = 
                        new KonkreterBeobachter1(konkretesSubjekt);
 
		// Zustandsänderung, Subjekt benachrichtigt
		// daraufhin die Beobachter, welche das jeweilige Subjekt
        // beobachten
		konkretesSubjekt.setStatus(1);
        konkretesSubjekt1.setStatus(3);
	}
}
Wie ersichtlich ist, wurde folgende Anmeldung an Subjekten durchgeführt:

konkretesSubjekt wird von KonkreterBeobachter und von KonkreterBeobachter2 beobachtet.

konkretesSubjekt1 wird nur von KonkreterBeobachter1 beobachtet.

Somit müssen wir für die Änderung von konkretesSubjekt eine Ausgabe von beiden Beobachtern erfolgen und für die Änderung von KonkretesSubjekt1 eine Textausgabe.

GitHub

Der Quelltext ist auf GitHub veröffentlicht.

Oberserver-Pattern auf GitHub
nach oben Java4Beginners -- Seitenversion 1.01 -- Stand: 2017-05-19