development:software-architecture:design-patterns:observer
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
development:software-architecture:design-patterns:observer [2024/08/13 07:20] – [Observer] tungnt | development:software-architecture:design-patterns:observer [2024/08/19 09:51] (current) – [Ví dụ 3:] tungnt | ||
---|---|---|---|
Line 10: | Line 10: | ||
{{ : | {{ : | ||
- | ====== Tham khảo | + | |
+ | **Sử dụng 2 interface có sẵn của PHP (SplSubject, | ||
+ | * http:// | ||
+ | * http:// | ||
+ | * https:// | ||
+ | |||
+ | ===== Ví dụ 1: ===== | ||
+ | |||
+ | <file php> | ||
+ | <?php | ||
+ | |||
+ | /** | ||
+ | * Subject, | ||
+ | */ | ||
+ | class Newspaper implements \SplSubject{ | ||
+ | private $name; | ||
+ | private $observers = array(); | ||
+ | private $content; | ||
+ | |||
+ | public function __construct($name) { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | //add observer | ||
+ | public function attach(\SplObserver $observer) { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | //remove observer | ||
+ | public function detach(\SplObserver $observer) { | ||
+ | |||
+ | $key = array_search($observer, | ||
+ | if($key){ | ||
+ | unset($this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | //set breakouts news | ||
+ | public function breakOutNews($content) { | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function getContent() { | ||
+ | return $this-> | ||
+ | } | ||
+ | |||
+ | //notify observers(or some of them) | ||
+ | public function notify() { | ||
+ | foreach ($this-> | ||
+ | $value-> | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Observer, | ||
+ | */ | ||
+ | class Reader implements SplObserver{ | ||
+ | private $name; | ||
+ | |||
+ | public function __construct($name) { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function update(\SplSubject $subject) { | ||
+ | echo $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | $newspaper = new Newspaper(' | ||
+ | |||
+ | $allen = new Reader(' | ||
+ | $jim = new Reader(' | ||
+ | $linda = new Reader(' | ||
+ | |||
+ | //add reader | ||
+ | $newspaper-> | ||
+ | $newspaper-> | ||
+ | $newspaper-> | ||
+ | |||
+ | //remove reader | ||
+ | $newspaper-> | ||
+ | |||
+ | //set break outs | ||
+ | $newspaper-> | ||
+ | |||
+ | // | ||
+ | //Allen is reading breakout news USA break down! (Newyork Times) | ||
+ | //Jim is reading breakout news USA break down! (Newyork Times) | ||
+ | </ | ||
+ | |||
+ | ===== Ví dụ 2: ===== | ||
+ | |||
+ | <file php> | ||
+ | <?php | ||
+ | |||
+ | // Example implementation of Observer design pattern: | ||
+ | |||
+ | class MyObserver1 implements SplObserver { | ||
+ | public function update(SplSubject $subject) { | ||
+ | echo __CLASS__ . ' - ' . $subject-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class MyObserver2 implements SplObserver { | ||
+ | public function update(SplSubject $subject) { | ||
+ | echo __CLASS__ . ' - ' . $subject-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class MySubject implements SplSubject { | ||
+ | private $_observers; | ||
+ | private $_name; | ||
+ | |||
+ | public function __construct($name) { | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function attach(SplObserver $observer) { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function detach(SplObserver $observer) { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function notify() { | ||
+ | foreach ($this-> | ||
+ | $observer-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public function getName() { | ||
+ | return $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | $observer1 = new MyObserver1(); | ||
+ | $observer2 = new MyObserver2(); | ||
+ | |||
+ | $subject = new MySubject(" | ||
+ | |||
+ | $subject-> | ||
+ | $subject-> | ||
+ | $subject-> | ||
+ | |||
+ | /* | ||
+ | will output: | ||
+ | |||
+ | MyObserver1 - test | ||
+ | MyObserver2 - test | ||
+ | */ | ||
+ | |||
+ | $subject-> | ||
+ | $subject-> | ||
+ | |||
+ | /* | ||
+ | will output: | ||
+ | |||
+ | MyObserver1 - test | ||
+ | */ | ||
+ | |||
+ | ?> | ||
+ | </ | ||
+ | |||
+ | ===== Ví dụ 3: ===== | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | <file php> | ||
+ | <?php | ||
+ | |||
+ | namespace RefactoringGuru\Observer\Conceptual; | ||
+ | |||
+ | /** | ||
+ | * PHP has a couple of built-in interfaces related to the Observer pattern. | ||
+ | * | ||
+ | * Here's what the Subject interface looks like: | ||
+ | * | ||
+ | * @link http:// | ||
+ | * | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | * | ||
+ | | ||
+ | | ||
+ | * | ||
+ | | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * There' | ||
+ | * | ||
+ | * @link http:// | ||
+ | * | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | */ | ||
+ | |||
+ | /** | ||
+ | * The Subject owns some important state and notifies observers when the state | ||
+ | * changes. | ||
+ | */ | ||
+ | class Subject implements \SplSubject | ||
+ | { | ||
+ | /** | ||
+ | * @var int For the sake of simplicity, the Subject' | ||
+ | * all subscribers, | ||
+ | */ | ||
+ | public $state; | ||
+ | |||
+ | /** | ||
+ | * @var \SplObjectStorage List of subscribers. In real life, the list of | ||
+ | * subscribers can be stored more comprehensively (categorized by event | ||
+ | * type, etc.). | ||
+ | */ | ||
+ | private $observers; | ||
+ | |||
+ | public function __construct() | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * The subscription management methods. | ||
+ | */ | ||
+ | public function attach(\SplObserver $observer): void | ||
+ | { | ||
+ | echo " | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function detach(\SplObserver $observer): void | ||
+ | { | ||
+ | $this-> | ||
+ | echo " | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Trigger an update in each subscriber. | ||
+ | */ | ||
+ | public function notify(): void | ||
+ | { | ||
+ | echo " | ||
+ | foreach ($this-> | ||
+ | $observer-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Usually, the subscription logic is only a fraction of what a Subject can | ||
+ | * really do. Subjects commonly hold some important business logic, that | ||
+ | * triggers a notification method whenever something important is about to | ||
+ | * happen (or after it). | ||
+ | */ | ||
+ | public function someBusinessLogic(): | ||
+ | { | ||
+ | echo " | ||
+ | $this-> | ||
+ | |||
+ | echo " | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Concrete Observers react to the updates issued by the Subject they had been | ||
+ | * attached to. | ||
+ | */ | ||
+ | class ConcreteObserverA implements \SplObserver | ||
+ | { | ||
+ | public function update(\SplSubject $subject): void | ||
+ | { | ||
+ | if ($subject-> | ||
+ | echo " | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class ConcreteObserverB implements \SplObserver | ||
+ | { | ||
+ | public function update(\SplSubject $subject): void | ||
+ | { | ||
+ | if ($subject-> | ||
+ | echo " | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * The client code. | ||
+ | */ | ||
+ | |||
+ | $subject = new Subject(); | ||
+ | |||
+ | $o1 = new ConcreteObserverA(); | ||
+ | $subject-> | ||
+ | |||
+ | $o2 = new ConcreteObserverB(); | ||
+ | $subject-> | ||
+ | |||
+ | $subject-> | ||
+ | $subject-> | ||
+ | |||
+ | $subject-> | ||
+ | |||
+ | $subject-> | ||
+ | </ | ||
+ | |||
+ | ===== Ví dụ 4: ===== | ||
+ | |||
+ | <file php> | ||
+ | <?php | ||
+ | |||
+ | namespace RefactoringGuru\Observer\RealWorld; | ||
+ | |||
+ | /** | ||
+ | * The UserRepository represents a Subject. Various objects are interested in | ||
+ | * tracking its internal state, whether it's adding a new user or removing one. | ||
+ | */ | ||
+ | class UserRepository implements \SplSubject | ||
+ | { | ||
+ | /** | ||
+ | * @var array The list of users. | ||
+ | */ | ||
+ | private $users = []; | ||
+ | |||
+ | // Here goes the actual Observer management infrastructure. Note that it's | ||
+ | // not everything that our class is responsible for. Its primary business | ||
+ | // logic is listed below these methods. | ||
+ | |||
+ | /** | ||
+ | * @var array | ||
+ | */ | ||
+ | private $observers = []; | ||
+ | |||
+ | public function __construct() | ||
+ | { | ||
+ | // A special event group for observers that want to listen to all | ||
+ | // events. | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | private function initEventGroup(string $event = " | ||
+ | { | ||
+ | if (!isset($this-> | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private function getEventObservers(string $event = " | ||
+ | { | ||
+ | $this-> | ||
+ | $group = $this-> | ||
+ | $all = $this-> | ||
+ | |||
+ | return array_merge($group, | ||
+ | } | ||
+ | |||
+ | public function attach(\SplObserver $observer, string $event = " | ||
+ | { | ||
+ | $this-> | ||
+ | |||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function detach(\SplObserver $observer, string $event = " | ||
+ | { | ||
+ | foreach ($this-> | ||
+ | if ($s === $observer) { | ||
+ | unset($this-> | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public function notify(string $event = " | ||
+ | { | ||
+ | echo " | ||
+ | foreach ($this-> | ||
+ | $observer-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Here are the methods representing the business logic of the class. | ||
+ | |||
+ | public function initialize($filename): | ||
+ | { | ||
+ | echo " | ||
+ | // ... | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function createUser(array $data): User | ||
+ | { | ||
+ | echo " | ||
+ | |||
+ | $user = new User(); | ||
+ | $user-> | ||
+ | |||
+ | $id = bin2hex(openssl_random_pseudo_bytes(16)); | ||
+ | $user-> | ||
+ | $this-> | ||
+ | |||
+ | $this-> | ||
+ | |||
+ | return $user; | ||
+ | } | ||
+ | |||
+ | public function updateUser(User $user, array $data): User | ||
+ | { | ||
+ | echo " | ||
+ | |||
+ | $id = $user-> | ||
+ | if (!isset($this-> | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | $user = $this-> | ||
+ | $user-> | ||
+ | |||
+ | $this-> | ||
+ | |||
+ | return $user; | ||
+ | } | ||
+ | |||
+ | public function deleteUser(User $user): void | ||
+ | { | ||
+ | echo " | ||
+ | |||
+ | $id = $user-> | ||
+ | if (!isset($this-> | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | unset($this-> | ||
+ | |||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Let's keep the User class trivial since it's not the focus of our example. | ||
+ | */ | ||
+ | class User | ||
+ | { | ||
+ | public $attributes = []; | ||
+ | |||
+ | public function update($data): | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * This Concrete Component logs any events it's subscribed to. | ||
+ | */ | ||
+ | class Logger implements \SplObserver | ||
+ | { | ||
+ | private $filename; | ||
+ | |||
+ | public function __construct($filename) | ||
+ | { | ||
+ | $this-> | ||
+ | if (file_exists($this-> | ||
+ | unlink($this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public function update(\SplSubject $repository, | ||
+ | { | ||
+ | $entry = date(" | ||
+ | file_put_contents($this-> | ||
+ | |||
+ | echo " | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * This Concrete Component sends initial instructions to new users. The client | ||
+ | * is responsible for attaching this component to a proper user creation event. | ||
+ | */ | ||
+ | class OnboardingNotification implements \SplObserver | ||
+ | { | ||
+ | private $adminEmail; | ||
+ | |||
+ | public function __construct($adminEmail) | ||
+ | { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function update(\SplSubject $repository, | ||
+ | { | ||
+ | // mail($this-> | ||
+ | // " | ||
+ | // " | ||
+ | |||
+ | echo " | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * The client code. | ||
+ | */ | ||
+ | |||
+ | $repository = new UserRepository(); | ||
+ | $repository-> | ||
+ | $repository-> | ||
+ | |||
+ | $repository-> | ||
+ | |||
+ | // ... | ||
+ | |||
+ | $user = $repository-> | ||
+ | " | ||
+ | " | ||
+ | ]); | ||
+ | |||
+ | // ... | ||
+ | |||
+ | $repository-> | ||
+ | </ | ||
+ | |||
+ | ===== Tham khảo ===== | ||
* https:// | * https:// | ||
- | * {{ :development: | + | * https:// |
+ | * https://medium.com/ | ||
+ | * https:// | ||
development/software-architecture/design-patterns/observer.1723533639.txt.gz · Last modified: 2024/08/13 07:20 by tungnt