php.de

Zurück   php.de > Webentwicklung > Software-Design

Software-Design Diskussionen auf Profi-Niveau: PHP Lösungen auf konzeptioneller Ebene

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 09.03.2010, 14:37  
Neuer Benutzer
 
Registriert seit: 09.03.2010
Beiträge: 23
PHP-Kenntnisse:
Anfänger
Kardey befindet sich auf einem aufstrebenden Ast
Standard [Erledigt] Observer-Pattern

Hallo,

ich beschäftige mich im Moment aus Interesse mit dem Observer-Pattern und habe dazu mehrere Fragen, die alle jedoch eher theoretischer Natur sind, sich also nicht auf schon vorhandene Implementationen beziehen.

Allgemein sieht das Entwurfsmuster implementiert ja in etwa so aus:
PHP-Code:
<?php

interface Observer {
    public function 
update(Observeable $victim);
}

interface 
Observeable {
    public function 
add(Observer $observer);
    public function 
remove(Observer $observer);
    public function 
notify();
}

class 
ObserveableClass implements Observeable {
    protected 
$observers = Array();

    public function 
add(Observer $observer) {
        
$this->observers[] = $observer;
    }
    public function 
remove(Observer $observer) {
        
$offset array_search($observer$this->observers);
        if(
$offset !== false) unset($this->observers[$offset]);
    }
    public function 
notify() {
        foreach(
$this->observers as $observer$observer->update($this);
    }
    public function 
doSomething() {
        
$this->notify();
    }
}

class 
ObservingClass implements Observer {
    public function 
update(Observeable $observedClass) {
        echo 
"I'm observing you!";
    }
}

class 
ObservingClass2 implements Observer {
    public function 
update(Observeable $observedClass) {
        echo 
"I'm observing you, too!";
    }
}
 
$observeableClass = new ObserveableClass();
$bigBrother = new ObservingClass();
$bigBrother2 = new ObservingClass2();

$observeableClass->add($bigBrother);
$observeableClass->doSomething();

// as exected: echos "I'm observing you!"

$observeableClass->remove($bigBrother);
$observeableClass->add($bigBrother2);
$observeableClass->doSomething();

// as exected: echos "I'm observing you, too!"

?>
Was spricht aber dagegen, Observeable und ObserveableClass so zu implementieren:
PHP-Code:
<?php 

// ...

abstract class Observeable {
    protected 
$observers = Array();

    public function 
add(Observer $observer) {
        
$this->observers[] = $observer;
    }
    public function 
remove(Observer $observer) {
        
$offset array_search($observer$this->observers);
        if(
$offset !== false) unset($this->observers[$offset]);
    }
    public function 
notify() {
        foreach(
$this->observers as $observer$observer->update($this);
    }
}

class 
ObserveableClass extends Observeable {
    public function 
doSomething() {
        
$this->notify();
    }
}

// ...

?>
Hieran finde ich persönlich schöner, dass ich nicht immer in der ObserveableClass jede der Methoden einzeln implementieren muss, zumal das Hinzufügen, Entfernen oder Informieren eines Observers (fast) immer gleich abläuft und man notfalls eine abweichende Methode die bestehende überschreiben kann.

Was mich aber immer noch stört, ist, dass wenn ich das Objekt erzeugt habe, zuerst immer noch die Observers hinzufügen muss, bevor ich mit dem Objekt arbeiten kann. Normalerweise sollte es ja im Programmablauf so sein, dass wenn beim Benutzer A ein ObserveableClass-Objekt instanziiert wird, beim Benutzer B das gleiche Objekt erzeugt wird - zumindest gleich bezogen auf die ObservingClasses. Dann ließe sich das Hinzufügen der Observers ja eigentlich auch in den Konstruktor verbannen:
PHP-Code:
<?php

interface Observer {
    public function 
update(Observeable $victim);
}

interface 
Observeable {
    public function 
add(Observer $observer);
    public function 
remove(Observer $observer);
    public function 
notify();
}

class 
ObserveableClass implements Observeable {
    protected 
$observers = Array();

    public function 
__construct() {
        
$bigBrother = new ObservingClass();
        
$this->add($bigBrother);
        
$this->doSomething();
    }
    public function 
add(Observer $observer) {
        
$this->observers[] = $observer;
    }
    public function 
remove(Observer $observer) {
        
$offset array_search($observer$this->observers);
        if(
$offset !== false) unset($this->observers[$offset]);
    }
    public function 
notify() {
        foreach(
$this->observers as $observer$observer->update($this);
    }
    public function 
doSomething() {
        
$this->notify();
    }
}

class 
ObservingClass implements Observer {
    public function 
update(Observeable $observedClass) {
        echo 
"I'm observing you!";
    }
}
 
$observeableClass = new ObserveableClass();

// as exected: echos "I'm observing you!"

?>
Somit hätte ich nach dem Instanziieren ein "fertiges" Objekt, mit dem ich weiterarbeiten kann.

Abschließend habe ich noch eine weitere Frage:
Ich habe einen fertigen Programmablauf, den ich jedoch mit einem PlugIn erweitern möchte. Dieses PlugIn soll im Grunde nichts Spektakuläres machen - beispielsweise wenn bei obigem Beispiel die doSomething()-Methode aufgerufen wird, das aktuelle Objekt serialisieren und irgendwo speichern, also irgendwie so:
PHP-Code:
<?php 

// ...

class ObservingClassS implements Observer {
    public function 
update(Observeable $observedClass) {
        
$serialized serizalize($observedClass);
        
// save
    
}
}

// ...

?>
Wie bekomme ich jetzt aber diesen Observer in mein fertiges Programm, ohne dieses zu verändern? Hierfür müsste ich ja den Observer meiner ObserveableClass bzw. meinen ObserveableClass-Objekt bekannt machen, was aber ohne Veränderung des bereits bestehenden Programmcodes nicht möglich ist - und dafür sind die Observers ja gerade da, dass man den Programmcode nicht verändern muss.

Könnte mir hier jemand weiterhelfen?
Kardey ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 09.03.2010, 14:49  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 34.241
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard

Puh, die zweite Frage, wäre besser als Anschluss gekommen.

Zu 1.1/
Interfaces dienen dazu, ein Objekt "als etwas" auszuzeichnen (und im Gegenzug eine bestimmte Funktionalität hinter einer wohldefinierten Schnittstelle == Methoden voraussetzen zu können).
Wenn ich bspw. meine Datenbankklasse observable "machen will", geht das oft nur mit Interfaces, weil die Klasse oft schon von woanders abgeleitet ist und so die Methoden direkt implementieren muss.
Zum zweiten schreibt ein Interface nur vor, was gemacht wird, nicht wie. Das ist ein sehr großer Vorteil, weil eine Implementierung wie in Codebox2/Observeable nicht für alle Objekte sinnvoll wäre.
Was Du machen kannst, ist, zwischen Interface und konkreter Klasse noch Deine abstrakte Basisklasse einfügen und für Objekte, die wirklich nur Observer sind und nichts grundlegende anderes, diese Klasse ableiten. Sehr sinnvoll wird das in den wenigsten Fällen sein. Dann besser so komponieren, wie Du es in Frage 1.2 versuchst.

Zu 1.2/
Zitat:
$bigBrother = new ObservingClass();
Macht eigentlich keinen Sinn. Es geht ja gerade darum, zwei Objekte unabhängig zu halten, während sie aber mehr oder weniger selbständig, anlassbezogen Daten austauschen können.
Ein Observer ist also kein Selbstzweck, sondern eine Komponente, die vom Observable Objekt bestimmte Sachen wissen muss. Deshalb sollte die entsprechende Objektinstanz von aussen kommen - dem Konstruktor zugewiesen oder eben via add zugeordnet.
Oder ums platt zu sagen: Stell Dir vor, der Observer ist der Chef (und ggf. Vorarbeiter) einer Firma, die Observables sind Mitarbeiter. Es macht jetzt keinen Sinn, für jeden Mitarbeiter seinen eigenen Chef einzustellen, denn es geht ja gerade darum, bestimmte Informationsstrukturen zu bündeln und darauf - Chef-seitig - zu reagieren (Aufforderung an den jeweiligen Mitarbeiter). Jedem Mitarbeiter wird also ein oder mehrere Ansprechpartner zugeordnet, die er zu benachrichtigen hat.
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--

Geändert von nikosch (09.03.2010 um 15:07 Uhr).
nikosch ist offline   Mit Zitat antworten
Alt 09.03.2010, 14:55  
Erfahrener Benutzer
 
Registriert seit: 29.10.2009
Beiträge: 113
PHP-Kenntnisse:
Fortgeschritten
mYkon befindet sich auf einem aufstrebenden Ast
Standard

Vielleicht auch noch interessant: Observer Pattern in PHP mit der SPL | Technik, Gothic und Anderes
mYkon ist offline   Mit Zitat antworten
Alt 09.03.2010, 15:12  
Neuer Benutzer
 
Registriert seit: 09.03.2010
Beiträge: 23
PHP-Kenntnisse:
Anfänger
Kardey befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von nikosch Beitrag anzeigen
Wenn ich bspw. meine Datenbankklasse observable "machen will", geht das oft nur mit Interfaces, weil die Klasse oft schon von woanders abgeleitet ist und so die Methoden direkt implementieren muss.
Okay, das stimmt, das würde dann ja Mehrfachverebung voraussetzen.

Zitat:
Zitat von nikosch Beitrag anzeigen
Zum zweiten schreibt ein Interface nur vor, was gemacht wird, nicht wie. Das ist ein sehr großer Vorteil, weil eine Implementierung wie in Codebox2/Observeable nicht für alle Objekte sinnvoll wäre.
Was Du machen kannst, ist, zwischen Interface und konkreter Klasse noch Deine abstrakte Basisklasse einfügen und für Objekte, die wirklich nur Observer sind und nichts grundlegende anderes, diese Klasse ableiten. Sehr sinnvoll wird das in den wenigsten Fällen sein.
Okay, da fehlt mir die praktische Erfahrung, da ich mich ja jetzt erst einmal damit beschäftige, aber wenn das in den meisten Fällen so ist, dass das unpraktisch ist, nehme ich das so hin .

Wie ich sehe, vervollständigst Du Deine Antwort stückchenweise. Ich werde das mit dieser Antwort genauso machen.

@mYkon: Vielen Dank für den Link, ich werde mir den Text mal durchlesen.
__________________
Kardey
Kardey ist offline   Mit Zitat antworten
Alt 09.03.2010, 15:22  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 34.241
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard

Zitat:
Wie ich sehe, vervollständigst Du Deine Antwort stückchenweise. Ich werde das mit dieser Antwort genauso machen.
Ja, tut mir leid, ist eigentlich kein so guter Stil, weil das Board sehr schnell ist und viele Infos evtl. gar nicht mehr wahrgenommen werden. Mir fielen aber noch einige Sachen ein.
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist offline   Mit Zitat antworten
Alt 09.03.2010, 15:28  
Neuer Benutzer
 
Registriert seit: 09.03.2010
Beiträge: 23
PHP-Kenntnisse:
Anfänger
Kardey befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von nikosch Beitrag anzeigen
Ja, tut mir leid, ist eigentlich kein so guter Stil, weil das Board sehr schnell ist und viele Infos evtl. gar nicht mehr wahrgenommen werden. Mir fielen aber noch einige Sachen ein.
Da braucht Dir doch nicht Leid zu tun .
Ich schreibe aber dann das, was ich noch ergänzen wollte, jetzt auch als neue Antwort, damit man später den Fluss des Themas noch halbwegs verfolgen kann .

Aber zu Deinem Beispiel mit dem Chef/der Ansprechperson und den Mitarbeitern: Ich habe das mal gerade schnell so implementiert:
PHP-Code:
<?php

// wie oben

class Worker implements Observeable {
    protected 
$observers = Array();
    protected 
$name '';
    
    public function 
__construct($name) {
        
$this->name $name;
    }
    public function 
getName() {
        return 
$this->name;
    }
    
// wie oben
    
public function finishWork() {
        
$this->notify();
    }
}

class 
Contact implements Observer {
    
// es wird natürlich ein observedObject übergeben, nicht wie oben geschrieben eine observedClass
    
public function update(Observeable $observedObject) {
        echo 
$observedObject->getName()." has finished their work.<br />";
    }
}
 
$worker1 = new Worker('1');
$worker2 = new Worker('2');
$worker3 = new Worker('3');

// Ein Ansprechpartner für alle drei Arbeiter -> nur ein Contact-Objekt.
$contact = new Contact();
$worker1->add($contact);
$worker2->add($contact);
$worker3->add($contact);

$worker1->finishWork();
$worker2->finishWork();
$worker3->finishWork();

?>
So hattest Du das doch gemeint, oder!? Würde ich immer im Konstruktor separat ein Observer-Objekt instanziieren, hätte ja jeder Arbeiter seinen eigenen Ansprechpartner, hier hingegen haben aber drei Arbeiter den gleichen Ansprechpartner.
__________________
Kardey
Kardey ist offline   Mit Zitat antworten
Alt 09.03.2010, 15:33  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 34.241
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard

Ja, so habe ich das gemeint. Bis auf dass "implements Observeable" glatt gelogen ist

[edit]

Eine etwas sinnvollere Anwendung wäre wahrscheinlich:
PHP-Code:
class Worker implements Observeable 
    
// ...

    
public function getStatus() {
        return(
$this->status);
    }

    public function 
hasQuestion() {
        
$this->status 'question';
        
$this->notify();
    }

    
// wie oben
    
public function finishWork() {
        
$this->status 'done';
        
$this->notify();
    }
}

class 
Contact implements Observer {
    
// es wird natürlich ein observedObject übergeben, nicht wie oben geschrieben eine observedClass
    
public function update(Observeable $observedObject) {
        switch 
$observedObject->getStatus() {

            case 
'done':
                
// mache Logbucheintrag, weise neuen Auftrag zu
                // $observedObject-> ..
                
break;

            case 
'question':
                
// rufe Mitarbeiter an
                // $observedObject-> ..
                
break;
        }
    }

__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--

Geändert von nikosch (09.03.2010 um 15:39 Uhr).
nikosch ist offline   Mit Zitat antworten
Alt 09.03.2010, 15:47  
Neuer Benutzer
 
Registriert seit: 09.03.2010
Beiträge: 23
PHP-Kenntnisse:
Anfänger
Kardey befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von nikosch Beitrag anzeigen
Ja, so habe ich das gemeint. Bis auf dass "implements Observeable" glatt gelogen ist
Zwischen getName() und doWork() verbirgt sich ein Kommentar .

Zu deinem EDIT: Ja, das macht wirklich mehr Sinn, als mein Beispiel.

Würde ich das ganze aber "automatisieren" wollen, dass also ein Worker-Objekt "erstellen" automatisch auch bedeutet, dass dem Arbeiter eine Ansprechperson zugewiesen wird, müsste ich da "fabrik-mäßig" dran gehen:
PHP-Code:
$worker1 WorkerFactory::getWorker('1'); 
wobei die Methode getWorker() dann automatisch einen Contact zuweist.

@mYkon: Ich habe mir in der Zwischenzeit den Text durchgelesen, den Du verlinkt hast. Er hat mir nicht wirklich etwas Neues gebracht, außer die Erkenntnis, sich vielleicht einmal mit der SPL zu beschäftigen. Trotzdem vielen Dank für den Link .
__________________
Kardey
Kardey ist offline   Mit Zitat antworten
Alt 09.03.2010, 15:58  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 34.241
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard

PHP-Code:
$pc    = new Contact ('Personalchef');
$va    = new Contact ('Vorarbeiter');
$boss = new Contact ('Boss');

$worker1 WorkerFactory::create ('1' 'Horst Horsten' $va);  
// besser:
$worker2 WorkerFactory::create ('2' 'Heinz Kunze');  
$worker2->addObserver ($pc); // "add" Methode ist nicht wirklich selbsterklärend
$worker2->addObserver ($va); 

// Achtung jetzt kommts :)
$va->addObserver ($pc); 
$pc->addObserver ($boss); 
__________________
--
One pixel is still too big. Please make it smaller. ASAP.

Initiative Mittelstand.
Die wichtigste Gestaltungsregel im Screendesign ist Pi mal Daumen des Arbeitgebers.
--
nikosch ist offline   Mit Zitat antworten
Alt 09.03.2010, 16:14  
Neuer Benutzer
 
Registriert seit: 09.03.2010
Beiträge: 23
PHP-Kenntnisse:
Anfänger
Kardey befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von nikosch Beitrag anzeigen
PHP-Code:
// Achtung jetzt kommts :)
$va->addObserver ($pc); 
$pc->addObserver ($boss); 
Das setzt dann ja aber voraus, dass Contact auch noch Observeable implementiert ... Macht man das in der Praxis überhaupt, also eine Observeable Observer-Klasse zu erstellen?

Das mit dem automatische Zuweisen der Contacts in der Factory hatte ich mir zwar anders vorgestellt, aber die Idee hat sich auch mittlerweile als unbrauchbar in Luft aufgelöst .
__________________
Kardey
Kardey ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Design Pattern BlackScorp PHP Tipps 2009 7 06.01.2010 19:04
[Erledigt] Crockfords Functional Pattern #fail phpdummi JavaScript, Ajax und mehr 1 20.06.2009 21:38
Welches Pattern? Creator PHP-Fortgeschrittene 19 14.04.2009 21:46
[Erledigt] preg_match und die Pattern Spoiler PHP Tipps 2009 9 13.02.2009 08:29
Formulargenerierung | Composite Pattern moveax1 PHP-Fortgeschrittene 13 27.01.2009 09:44
preg_replace: Gleiche Platzhalter im Pattern Lavalampe PHP Tipps 2009 5 16.01.2009 21:42
Singleton Pattern Verstaendisproblem Luka PHP Tipps 2008 13 19.12.2008 19:00
PHP Command Pattern = Module? meGa Software-Design 4 14.12.2008 12:35
[Erledigt] Formularvalidierung, preg_match pattern Problem moveax1 PHP Tipps 2008 4 12.12.2008 16:48
Design Pattern Harry B. Software-Design 7 02.09.2008 20:49
Bild vor Link pattern TimmaY PHP Tipps 2007 5 21.03.2007 18:06
Events, Observer, Henne-Ei-Problem Basti PHP-Fortgeschrittene 3 09.05.2006 15:53
Folgendes Pattern PHP Tipps 2005 5 01.03.2005 12:41
Probleme mit Pattern bei Templateersetzung RudiS PHP-Fortgeschrittene 2 19.02.2005 22:09
preg_match --> pattern PHP Tipps 2004 4 27.08.2004 18:12

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
observer pattern, php observer pattern, observer pattern php, php observer, observer php, php observer klasse, php design patterns observer, php interface observer, array_search pattern, pattern observer, php observer pattern sinnvoll?, observer pattern php validation, php obserer pattern, php event pattern, an object mit inrterface observer anhängen, php observern pattern beispiel, sinn observer pattern, php observer pattern example, observern pattern datenbank php, php implements observer

Alle Zeitangaben in WEZ +1. Es ist jetzt 04:19 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum