Ankündigung

Einklappen
Keine Ankündigung bisher.

[Erledigt] Observer-Pattern

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [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

  • #2
    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/
    $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.
    [COLOR="#F5F5FF"]--[/COLOR]
    [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
    „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
    [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
    [COLOR="#F5F5FF"]
    --[/COLOR]

    Kommentar


    • #3
      Vielleicht auch noch interessant: Observer Pattern in PHP mit der SPL | Technik, Gothic und Anderes

      Kommentar


      • #4
        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 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

        Kommentar


        • #5
          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.
          [COLOR="#F5F5FF"]--[/COLOR]
          [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
          „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
          [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
          [COLOR="#F5F5FF"]
          --[/COLOR]

          Kommentar


          • #6
            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

            Kommentar


            • #7
              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;
                      }
                  }

              [COLOR="#F5F5FF"]--[/COLOR]
              [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
              „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
              [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
              [COLOR="#F5F5FF"]
              --[/COLOR]

              Kommentar


              • #8
                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

                Kommentar


                • #9
                  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); 
                  [COLOR="#F5F5FF"]--[/COLOR]
                  [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
                  „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                  [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
                  [COLOR="#F5F5FF"]
                  --[/COLOR]

                  Kommentar


                  • #10
                    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

                    Kommentar


                    • #11
                      Das setzt dann ja aber voraus, dass Contact auch noch Observeable implementiert ...
                      Selbstredend
                      Macht man das in der Praxis überhaupt, also eine Observeable Observer-Klasse zu erstellen?
                      Es gibt nicht das Pattern. Im konkreten Anwendungsfall einer Personalhierarchie würde das schon Sinn machen. Und technisch möglich ist das ja (man muss nur auf Endlosschleifen achten).

                      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
                      Ja, das ist verhältnismäßig unpraktisch über eine Factroymethode. Es ginge natürlich auch so:

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

                      $BaseWorkerFactory = new WorkerFactory;
                      $BaseWorkerFactory->setObservers (array ($va));

                      $PrioBaseWorkerFactory = new WorkerFactory;
                      $PrioBaseWorkerFactory->setObservers (array ($va $pc));


                      $worker1 $BaseWorkerFactory->create ('1' 'Horst Horsten');  
                      $worker2 $PrioBaseWorkerFactory->create ('2' 'Heinz Kunze');  

                      // usw. 
                      [COLOR="#F5F5FF"]--[/COLOR]
                      [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
                      „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                      [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
                      [COLOR="#F5F5FF"]
                      --[/COLOR]

                      Kommentar


                      • #12
                        Zitat von nikosch Beitrag anzeigen
                        ... (man muss nur auf Endlosschleifen achten).
                        Daran hatte ich schon gedacht, was ja durchaus, wenn man nicht aufpasst, bei einer komplexeren Hierarchie passieren könnte.

                        Zitat von nikosch Beitrag anzeigen
                        Es ginge natürlich auch so: ....
                        So etwas hatte ich mir im Prinzip auch vorgestellt, nur waren bei mir die Contacts mehr oder weniger fest in der Fabrik verankert und die Contacts waren auch eher nach dem Motto da "Hauptsache jeder Worker hat ein Contact, aber die Contacts an sich interessieren mich nicht.", aber die Idee hat sich dann doch schnell als unpraktisch erwiesen.
                        Kardey

                        Kommentar


                        • #13
                          Hoffentlich ist dieser Beitrag nicht zuuuu lange geworden .

                          Hallo,

                          ich habe das Beispiel mit den Arbeitern, dem Ansprechpartner und dem Chef mal etwas ausgebaut, um das Zusammenspiel der Observers aktiv zu sehen.
                          Die beiden Interfaces bleiben unverändert (mit Ausnahme verbesserter Methodennamen):
                          PHP-Code:
                          interface Observer {
                              
                              public function 
                          update(Observeable $observedObject);
                              
                          }

                          interface 
                          Observeable {
                              
                              public function 
                          addObserver(Observer $observer);
                              
                              public function 
                          removeObserver(Observer $observer);
                              
                              public function 
                          notifyObservers();


                          Dann habe ich noch zwei Klassen erstellt: eine für die verschiedenen Jobs und eine, die die in der Firma vorhandenen Jobs sammelt (wobei diese Klassen nur der Verwendung in diesem Beispiel dienen sollen, also nicht unbedingt schön sein sollen/müssen ):
                          PHP-Code:
                          class Job {

                              protected 
                          $worker null;
                              protected 
                          $title '';
                              protected 
                          $decription '';
                              protected 
                          $done false;
                              
                              public function 
                          __construct($title$description '') {
                                  
                          $this->title $title;
                                  
                          $this->description $description;
                              }
                              
                              public function 
                          assignWorker(Worker $worker) {
                                  
                          $this->worker $worker;
                              }
                              
                              public function 
                          markAsDone() {
                                  
                          $this->done true;
                              }
                              
                              public function 
                          getTitle() {
                                  return 
                          $this->title;
                              }

                          }

                          class 
                          Jobs {
                              
                              protected static 
                          $jobs = array();

                              public static function 
                          addJob(Job $job) {
                                  
                          self::$jobs[] = $job;
                              }
                              
                              public static function 
                          hasJobs() {
                                  return 
                          count(self::$jobs) !== 0;
                              }
                              
                              public static function 
                          getJob() {
                                  
                          $jobIndex array_rand(self::$jobs);
                                  
                          $job self::$jobs[$jobIndex];
                                  unset(
                          self::$jobs[$jobIndex]);
                                  return 
                          $job;
                              }
                              

                          Dann die Klasse Worker, die Observeable implementiert und noch ein paar "Worker-spezifische" Attribute und Methoden enthält:
                          PHP-Code:
                          class Worker implements Observeable 

                              protected 
                          $observers = Array();
                              
                              protected 
                          $finishedJobs = array();
                              protected 
                          $finishedJobsCount 0;
                              public 
                          $currentJob null;
                              protected 
                          $name '';
                              protected 
                          $status 'sleeping';
                              const 
                          JOBS_PER_DAY 6;
                              
                              public function 
                          __construct($name) {
                                  
                          $this->name $name;
                                  
                          $this->status 'awake';
                              }
                              
                              public function 
                          addObserver(Observer $observer) {
                                  
                          $this->observers[] = $observer;
                              }
                              
                              public function 
                          removeObserver(Observer $observer) {
                                  
                          $offset array_search($observer$this->observers);
                                  if(
                          $offset !== false) unset($this->observers[$offset]);
                              }
                              
                              public function 
                          notifyObservers() {
                                  foreach(
                          $this->observers as $observer$observer->update($this);
                              }

                              public function 
                          getName() {
                                  return 
                          $this->name;
                              }
                              
                              public function 
                          getStatus() {
                                  return 
                          $this->status;
                              }
                              
                              public function 
                          startWorking() {
                                  echo 
                          $this->getName().': I start working!<br />';
                                  
                          $this->status 'working';
                                  while(
                          $this->finishedJobsCount self::JOBS_PER_DAY) {
                                      if(
                          is_null($this->currentJob)) {
                                          
                          $this->getJob();
                                      }
                                      
                          $this->finishJob();
                                  }
                                  
                          $this->status 'doneForToday';
                                  echo 
                          $this->getName().": I'm done for today.<br />";
                                  
                          $this->notifyObservers();
                              }
                              
                              public function 
                          addFinishedJob(Job $job) {
                                  
                          $this->finishedJobs[] = $job;
                              }
                              
                              public function 
                          getJob() {
                                  
                          $this->status 'needJob';
                                  
                          $this->notifyObservers();
                              }

                              public function 
                          finishJob() {
                                  
                          $this->status 'done';
                                  
                          $this->finishedJobsCount++;
                                  
                          $this->notifyObservers();
                              }
                              

                          Das "Grundprinzip" hierbei ist: Worker instanziieren, Observer zuweisen, arbeiten (-> Job bekommen, Job abarbeiten und direkt neuen Job bekommen, sollte das Arbeitspensum noch nicht erschöpft sein) und sich verabschieden.
                          Neben dem Worker gibt es noch die Contacts:
                          PHP-Code:
                          class Contact implements ObserverObserveable {
                              
                              protected 
                          $observers = Array();
                              
                              protected 
                          $name '';
                              protected 
                          $status '';
                              
                              public function 
                          __construct($name) {
                                  
                          $this->name $name;
                                  
                          $this->status 'working';
                              }
                              
                              public function 
                          getName() {
                                  return 
                          $this->name;
                              }
                              
                              public function 
                          getStatus() {
                                  return 
                          $this->status;
                              }
                              
                              public function 
                          update(Observeable $observedObject) {
                                  switch (
                          $observedObject->getStatus()) {
                                      case 
                          'done':
                                          
                          $observedObject->currentJob->markAsDone();
                                          
                          $observedObject->addFinishedJob($observedObject->currentJob);
                                          echo 
                          $observedObject->getName().': '.$observedObject->currentJob->getTitle().' finished!<br />';
                                      case 
                          'needJob':
                                          if(!
                          Jobs::hasJobs()) {
                                              echo 
                          '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'.$this->getName().': I need new Jobs!<br />';
                                              
                          $this->status 'needJobs';
                                              
                          $this->notifyObservers();
                                              
                          $this->status 'working';
                                          }
                                          
                          $job Jobs::getJob();
                                          
                          $job->assignWorker($observedObject);
                                          
                          $observedObject->currentJob $job;
                                          break;
                                      case 
                          'doneForToday':
                                          
                          $this->sayGoodbye($observedObject->getName());
                                          break;
                                  }
                              }
                              
                              protected function 
                          sayGoodbye($workerName) {
                                  echo 
                          $this->getName().': See you tomorrow, '.$workerName.'!';
                              }
                              
                              public function 
                          addObserver(Observer $observer) {
                                  
                          $this->observers[] = $observer;
                              }
                              
                              public function 
                          removeObserver(Observer $observer) {
                                  
                          $offset array_search($observer$this->observers);
                                  if(
                          $offset !== false) unset($this->observers[$offset]);
                              }
                              
                              public function 
                          notifyObservers() {
                                  foreach(
                          $this->observers as $observer$observer->update($this);
                              }


                          die die Worker beobachten, ihm einen ersten Job (-> 'needJob') und die weitere Jobs (-> 'done') zuweisen und sie verabschieden (-> 'doneForToday').

                          Zuletzt gibt es noch den Boss:
                          PHP-Code:
                          class Boss implements Observer {
                              
                              public function 
                          update(Observeable $observedObject) {
                                  switch (
                          $observedObject->getStatus()) {
                                      case 
                          'needJobs':
                                          echo 
                          '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Boss: Here are 10 new Jobs!<br />';
                                          
                          $this->getJobs();
                                          break;
                                  }
                              }
                              
                              protected function 
                          getJobs() {
                                  for(
                          $i 1$i <= 10$i++) {
                                      
                          Jobs::addJob(new Job(mt_rand(5100).'. job'));
                                  }
                              }


                          der neue Jobs ordert, wenn ihn ein Contact informiert, dass keine Jobs mehr da sind.

                          Mein Beispielablauf sieht wie folgt aus:
                          PHP-Code:
                          $job1 = new Job('1. job');
                          $job2 = new Job('2. job');
                          $job3 = new Job('3. job');
                          $job4 = new Job('4. job');

                          Jobs::addJob($job1);
                          Jobs::addJob($job2);
                          Jobs::addJob($job3);
                          Jobs::addJob($job4);

                          $boss = new Boss();

                          $contact = new Contact('Kardey\'s Ansprechpartner');
                          $contact->addObserver($boss);

                          $worker = new Worker('Kardey');
                          $worker->addObserver($contact);
                          $worker->startWorking(); 
                          und er liefert auch das, was er soll:
                          Code:
                          Kardey: I start working!
                          Kardey: 2. job finished!
                          Kardey: 1. job finished!
                          Kardey: 4. job finished!
                          Kardey: 3. job finished!
                               Kardey's Ansprechpartner: I need new Jobs!
                                    Boss: Here are 10 new Jobs!
                          Kardey: 61. job finished!
                          Kardey: 56. job finished!
                          Kardey: I'm done for today.
                          Kardey's Vorarbeiter: See you tomorrow, Kardey!
                          Wäre das in diesem Zusammenhang auch ein (halbwegs) vernüntiges Beispiel, um das Observer-Pattern in der Praxis einzusetzen?

                          Bevor ich nochmal die zweite Frage aus meinem Ausgangsbeitrag aufnehmen möchte, habe ich noch eine "Detail-Frage":
                          Wenn der Worker einen Job abgearbeitet hat, fügt der Contact diesen Job ins $finishedJobs-Array des Workers ein (damit der Worker nachher eine Übersicht hat, welche Jobs er begearbeitet hat, oder warum auch immer ). Dafür benötige ich die Methode addFinishedJob(Job $job) des Workers. Wie kann ich hier aber verhindern, dass der Worker die Methode selbst aufruft, ohne den Job überhaupt ausgeführt zu haben? Es müsste also sicher gestellt sein, dass die Methode nur von Contacts aufgerufen werden kann.
                          Kardey

                          Kommentar


                          • #14
                            halbwegs
                            Meine Kritik wäre, dass Observer-Pattern ja eigentlich eine Art Parallelität abbilden, die bei Dir nicht gegeben ist, da immer nur ein Worker seine Jobs per Schleife abarbeiten kann. Aus Sicht des Workers funktionierts, global macht das so wenig Sinn.
                            Wenn der Worker einen Job abgearbeitet hat, ...
                            Naja, es ist ganz einfach: Im wahren Leben machst Du Deine Liste oder Dein Chef seine. Wenn Chef das personenbezogen machen will, dann muss er selbst dafür sorgen (assoz. Array)
                            [COLOR="#F5F5FF"]--[/COLOR]
                            [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
                            „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                            [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
                            [COLOR="#F5F5FF"]
                            --[/COLOR]

                            Kommentar


                            • #15
                              Zitat von nikosch Beitrag anzeigen
                              Meine Kritik wäre, dass Observer-Pattern ja eigentlich eine Art Parallelität abbilden, die bei Dir nicht gegeben ist, da immer nur ein Worker seine Jobs per Schleife abarbeiten kann. Aus Sicht des Workers funktionierts, global macht das so wenig Sinn.
                              Okay, trotzdem intensivem Nachdenken muss ich gestehen, dass ich nicht wirklich verstanden habe, was das bedeuten soll .
                              (Trotzdem mal meine Gedanken dazu: Meinst Du mit der "Parallelität", dass mehrere Workers "gleichzeitig" aktiv sind, oder das die Workers gleichzeitig mehrere andere Objekte "verändern", wie es beim Beispiel auf Wikipedia der Fall ist (Messergebnisse und ihre Darstellung in verschiedenen Diagrammen)?)

                              Könnte vielleicht jemand ein praktisches Beispiel "liefern", dass auch irgendwo implementiert ist, also auch in der Praxis angewandt wird?
                              Kardey

                              Kommentar

                              Lädt...
                              X