23 - seeren-training/Design-Pattern GitHub Wiki

Observer

  • 🔖 Définition
  • 🔖 Implémentation

📑 Définition

Quels problèmes le design pattern Observer peut-il résoudre ?

  • Une dépendance un-à-plusieurs entre les objets doit être définie sans que les objets soient étroitement couplés.
  • Il faut s'assurer que lorsqu'un objet change d'état, un nombre illimité d'objets dépendants est mis à jour automatiquement.
  • Il devrait être possible qu'un objet puisse notifier un nombre illimité d'autres objets.

image

Quelle solution le modèle de conception Observer décrit-il ?

  • Définissez les objets Sujet et Observateur de sorte que lorsqu'un sujet change d'état, tous les observateurs enregistrés sont notifiés et mis à jour automatiquement (et probablement de manière asynchrone).

📑 Implémentation

Observer

abstract class Observer
{

    abstract public function update(Subject $subject): void;

}

Subject

abstract class Subject
{

    private array $observers = [];

    public function attach(Observer $observer)
    {
        $this->observers[] = $observer;
    }

    public function detach(Observer $observer)
    {
        $key = array_search($observer, $this->observers);
        if (false !== $key) {
            array_splice($this->observers, $key, 1);
        }
    }

    public function notify(): void
    {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }

}

Concrete Observer

class ConcreteLoggerObserver extends Observer
{

    public function update(Subject $subject): void
    {
        echo "Log event:" . (string) $subject . PHP_EOL;
    }

}

Concrete Subject

class ConcreteFileReaderSubject extends Subject
{

    private int $lineNumber;

    public function readFile($fileName)
    {
        $this->lineNumber = 0;
        $fn = fopen($fileName,"r");
        while(!feof($fn))  {
            $result = fgets($fn);
            $this->lineNumber++;
            $this->notify();
        }
        fclose($fn);
    }

    public function __toString(): string
    {
        return $this->lineNumber . " line read";
    }

}

Utilisation

$logger = new ConcreteLoggerObserver();
$reader = new ConcreteFileReaderSubject();
$reader->attach($logger);
$reader->readFile(__FILE__);