Observer Pattern

geposted am 13.03.2020, in PHP

Um ein Veröffentlichungs-/Abonnementverhalten für ein Objekt zu implementieren, werden die angefügten "Beobachter" benachrichtigt, wenn ein "Subject"-Objekt seinen Status ändert. Es wird verwendet, um die Menge der gekoppelten Objekte zu verkürzen und verwendet stattdessen lose Kopplung.

Subject, dem Observer zugeordnet werden

<?php

namespace DesignPatterns\Behavioral\Observer;

use SplSubject;
use SplObjectStorage;
use SplObserver;

/**
 * User implements the observed object (called Subject), it maintains a list of observers and sends notifications to
 * them in case changes are made on the User object
 */
class Subject implements SplSubject
{
    private $email;
    private $observers;

    public function __construct()
    {
        $this->observers = new SplObjectStorage();
    }

    public function attach(SplObserver $observer)
    {
        $this->observers->attach($observer);
    }

    public function detach(SplObserver $observer)
    {
        $this->observers->detach($observer);
    }

    public function changeEmail(string $email)
    {
        $this->email = $email;
        $this->notify();
    }

    public function notify()
    {
        /** @var SplObserver $observer */
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
}

Observer

<?php

namespace DesignPatterns\Behavioral\Observer;

use SplObserver;
use SplSubject;

class SubjectObserver implements SplObserver
{
    /**
     * @var SplSubject[]
     */
    private $changedSubjects = [];

    /**
     * It is called by the Subject, usually by SplSubject::notify()
     */
    public function update(SplSubject $subject)
    {
        $this->changedSubjects[] = clone $subject;
    }

    /**
     * @return SplSubject[]
     */
    public function getChangedSubjects(): array
    {
        return $this->changedSubjects;
    }
}

 

Test (Implementation)

<?php

namespace DesignPatterns\Behavioral\Observer\Tests;

use DesignPatterns\Behavioral\Observer\Subject;
use DesignPatterns\Behavioral\Observer\SubjectObserver;
use PHPUnit\Framework\TestCase;

class ObserverTest extends TestCase
{
    public function testChangeInUserLeadsToUserObserverBeingNotified()
    {
        $observer = new SubjectObserver();

        $subject = new Subject();
        $subject->attach($observer);

        $subject->changeEmail('foo@bar.com');
        $this->assertCount(1, $observer->getChangedSubjects());
    }
}