Today we talk about the observer mode, which is a very common mode on which many events are distributed.
Here we will talk about the use of this pattern from one topic, with the following:
A newspaper in a city opens and citizens subscribe to newspapers to try to solve the problem using the observer model.
Before using the observer mode, let's talk about general processing.
class Publisher { public $title = ''; public function __construct($title) { $this->title = $title; } public function push() { echo "[{$this->title}]Publish News" . PHP_EOL; } } class People { public $name = ''; public function __construct($name) { $this->name = $name; } public function pull(Publisher $publisher) { echo "[{$this->name}]Received{$publisher->title}]Published News" . PHP_EOL; } } /* Initialize User */ $peoples = []; for ($i = 1; $i <= 5; $i++) { $peoples[] = new People("user{$i}"); } /* Newspapers use the push method to publish news */ $publisher = new Publisher("Newspaper 1"); $publisher->push(); /* All subscribed citizens use pull method to receive newspaper objects */ foreach ($peoples as $people) { $people->pull($publisher); }
Every time a publishier uses the push method, it needs to loop through $peoples for notification, which can be encapsulated in a function and called each time.
The following is a running screenshot:
The above code is certainly working without any problems and is particularly easy to understand.Once the push method is run, the pull method is called in a loop.But each call is particularly cumbersome, what better?
Take a look at the following code:
class Publisher { public $title = ''; private $peoples = []; public function __construct($title, $peoples) { $this->title = $title; $this->peoples = $peoples; } public function push() { echo "[{$this->title}]Publish News" . PHP_EOL; // Notify all subscribers as soon as the news is published foreach ($this->peoples as $people) { // Notice here that $this $people->pull($this); } } } // The original Peple class is unchanged, omitted here $peoples = []; for ($i = 1; $i <= 5; $i++) { $peoples[] = new People("user{$i}"); } // When creating $publisher, pass $peoples directly to the newspaper $publisher = new Publisher("Newspaper 1", $peoples); $publisher->push();
Here you can see that the loop has been moved into the Publisher class and that all people objects receive messages each time the push method is executed.
But here, $peoples is passed in through a constructor, can it be separated?
Now rewrite the code:
class Publisher { public $title = ''; private $peoples = []; public function __construct($title) { $this->title = $title; } public function addPeople(People $people) { $this->peoples[] = $people; } public function push() { echo "[{$this->title}]Publish News" . PHP_EOL; foreach ($this->peoples as $people) { $people->pull($this); } } } // Client $publisher = new Publisher("Newspaper 1"); for ($i = 1; $i <= 5; $i++) { $publisher->addPeople(new People("user{$i}")); } $publisher->push();
It is very convenient and clear to use this way.
That's the embryo of the observer model, and then the abstraction...
interface IObserver { public function update(Publisher $publisher); } class Publisher { public $title = ''; private $observers = []; public function __construct($title) { $this->title = $title; } public function attach(IObserver $observer) { $this->observers[] = $observer; } public function push() { echo "[{$this->title}]Publish News" . PHP_EOL; foreach ($this->observers as $observer) { $observer->update($this); } } } class People implements IObserver { public $name = ''; public function __construct($name) { $this->name = $name; } public function update(Publisher $publisher) { echo "[{$this->name}]Received{$publisher->title}]Published News" . PHP_EOL; } } $publisher = new Publisher("Newspaper 1"); for ($i = 1; $i <= 5; $i++) { $publisher->attach(new People("user{$i}")); } $publisher->push();
These are the more standard observer mode structures, and it is important to note that the update method parameters defined in the IObserver interface can be modified to suit the needs of the scenario.
Another thing to mention is that in the Publisher class, you can create a detach method to unsubscribe from.This makes the whole management of $peoples relatively complete.
In fact, sometimes I think learning design mode should not be too dead, as long as the idea is correct, you can write it anyway.