Observer Pattern where walls have ears
Everyone must have logged in to the system. After verifying the username and password, the login is successful. The log system should record the login. If there is a login error, the security system should record the error. The email system should also send relevant emails to the administrator. etc. This is like the login system being monitored by many people. Once there is any trouble, other systems will immediately learn about it. Then try using the observer mode. The class diagram is as follows:
Very simple mode, implementation code:
Php code
<?php interface Observable{ function attach( Observer $observer ); function detach( Observer $observer ); function notify(); } class login implements Observable{ const LOGIN_USER_UNKNOW = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array(); private $observers = array(); public function setStatus( $status, $user, $ip ) { $this->status = array( $status, $user, $ip ); } public function getStatus() { return $this->status; } public function handleLogin( $user, $pass, $ip ) { switch ( mt_rand( 1, 3 ) ) { case 1: $this->setStatus( self::LOGIN_USER_UNKNOW, $user, $ip ); $ret = false; break; case 2: $this->setStatus( self::LOGIN_WRONG_PASS, $user, $ip ); $ret = false; break; case 3: $this->setStatus( self::LOGIN_ACCESS, $user, $ip ); $ret = true; break; } $this->notify(); return $ret; } public function attach( Observer $observer ) { $this->observers[] = $observer; } public function detach( Observer $observer ) { $newObservers = array(); foreach ( $this->observers as $obs ) { if ( $obs !== $observer ) $newObservers[] = $obs; } $this->observers = $newObservers; } public function notify() { foreach ( $this->observers as $obs ) { $obs->update( $this ); } } } interface Observer{ function update( Observable $observable ); } class SecurityMonitor implements Observer{ function update( Observable $observable ) { $status = $observable->getStatus(); if($status[0] == Login::LOGIN_WRONG_PASS){ echo __CLASS__.":".$status[1]."于".$status[2]."登录失败"; } } } $login = new Login(); $login->attach(new SecurityMonitor()); $login->handleLogin('XXX','XXX','127.0.0.1'); ?>
Running results when an error occurs:
SecurityMonitor:XXX at 127.0. 0.1 Login failed [Finished in 0.1s]
You can see in the code that the login object actively adds the SecurityMonitor object for observation. In this way, to call Login::getStatus(), the SecurityMonitor class must know more information. Although the call occurs on an ObServable object, there is no guarantee that the object is also a Login object. To solve this problem, there is a way: keep the ObServable interface generic intermittently, and the ObServer class is responsible for ensuring that their bodies are of the correct type. They can even add themselves to the subject. The class diagram is as follows:
The implementation code is as follows:
Php code
<?php interface Observable{ function attach( Observer $observer ); function detach( Observer $observer ); function notify(); } class login implements Observable{ const LOGIN_USER_UNKNOW = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array(); private $observers = array(); public function setStatus( $status, $user, $ip ) { $this->status = array( $status, $user, $ip ); } public function getStatus() { return $this->status; } public function handleLogin( $user, $pass, $ip ) { switch ( mt_rand( 1, 3 ) ) { case 1: $this->setStatus( self::LOGIN_USER_UNKNOW, $user, $ip ); $ret = false; break; case 2: $this->setStatus( self::LOGIN_WRONG_PASS, $user, $ip ); $ret = false; break; case 3: $this->setStatus( self::LOGIN_ACCESS, $user, $ip ); $ret = true; break; } $this->notify(); return $ret; } public function attach( Observer $observer ) { $this->observers[] = $observer; } public function detach( Observer $observer ) { $newObservers = array(); foreach ( $this->observers as $obs ) { if ( $obs !== $observer ) $newObservers[] = $obs; } $this->observers = $newObservers; } public function notify() { foreach ( $this->observers as $obs ) { $obs->update( $this ); } } } interface Observer{ function update( Observable $observable ); } //以上代码和上例是一样的 abstract class LoginObserver implements Observer{ private $login; public function __construct( Login $login ) { $this->login = $login; $login->attach( $this ); } public function update( Observable $observable ) { if ( $this->login === $observable ) $this->doUpdate( $observable ); } abstract function doUpdate( Login $login ); } class SecurityMonitor extends LoginObserver{ public function doUpdate( Login $login ) { $status = $login->getStatus(); if ( $status[0] == Login::LOGIN_WRONG_PASS ) echo __CLASS__.":".$status[1]."于".$status[2]."登录失败"; } } $login = new Login(); new SecurityMonitor($login);//<strong>此外login对象是被动被观察的</strong> $login->handleLogin( 'XXX', 'XXX', '127.0.0.1' ); ?>
The running result is the same as the above example
After php5, the built-in SPL extension provides native support for the observer mode. After improving the above example through SPL:
Php code
<?php class login implements SplSubject{ const LOGIN_USER_UNKNOW = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array(); // private $observers = array(); private $storage; public function __construct() { $this->storage = new SplObjectStorage(); } public function setStatus( $status, $user, $ip ) { $this->status = array( $status, $user, $ip ); } public function getStatus() { return $this->status; } public function handleLogin( $user, $pass, $ip ) { switch ( mt_rand( 1, 3 ) ) { case 1: $this->setStatus( self::LOGIN_USER_UNKNOW, $user, $ip ); $ret = false; break; case 2: $this->setStatus( self::LOGIN_WRONG_PASS, $user, $ip ); $ret = false; break; case 3: $this->setStatus( self::LOGIN_ACCESS, $user, $ip ); $ret = true; break; } $this->notify(); return $ret; } public function attach( SplObserver $observer ) { $this->storage->attach( $observer ); } public function detach( SplObserver $observer ) { $this->storage->detach( $observer ); } public function notify() { foreach ( $this->storage as $obs ) { $obs->update( $this ); } } } abstract class LoginObserver implements SplObserver{ private $login; public function __construct( Login $login ) { $this->login = $login; $login->attach( $this ); } public function update( SplSubject $subject ) { if ( $this->login === $subject ) $this->doUpdate( $subject ); } abstract function doUpdate( Login $login ); } class SecurityMonitor extends LoginObserver{ public function doUpdate( Login $login ) { $status = $login->getStatus(); if ( $status[0] == Login::LOGIN_WRONG_PASS ) echo __CLASS__.":".$status[1]."于".$status[2]."登录失败"; } } $login = new Login(); new SecurityMonitor( $login ); $login->handleLogin( 'XXX', 'XXX', '127.0.0.1' ); ?>
The code has been written, but you still need to understand some theory.
Definition of Observer Pattern
Define a one-to-many dependency relationship between objects, so that whenever an object changes state, all objects that depend on it will be notified and automatically updated. The observer pattern consists of four roles:
1. Subject Observed
Defines the responsibilities that the observed must implement. It must be able to dynamically add and cancel observers. It is generally an abstract class or an implementation class, which only fulfills the responsibilities that must be implemented as an observer, manages observers and passes observers.
2. Observer
After receiving the message, the observer will perform an update operation and process the received information.
3. ConcreteSubject’s specific observable
defines the observable’s own business logic and also defines which events will be notified.
4. ConcreteObserver specific observer
Each observation has a different processing response after receiving the message, and each observer has its own processing logic.
Advantages of the observer pattern
1. There is an abstract coupling between the observer and the observed
Designed in this way, it is very easy to expand whether adding observers or observed objects, and it is already available in java and php The definition of the abstract level of implementation is even more convenient in terms of system expansion.
2. Establish a trigger mechanism
According to the single responsibility principle, each class has a single responsibility. So how to connect each single responsibility into a complex logical relationship in the real world? The observer pattern can perfectly realize the chain form here
Disadvantages of the observer pattern
The observer pattern needs to consider the issues of development efficiency and operating efficiency. One observer, multiple observers, development and Debugging will be more complicated, and in PHP, message notifications are executed sequentially. If an observer is stuck, it will affect the overall execution efficiency. In this case, asynchronous methods are generally considered. The efficiency of multi-stage triggering is even more worrying, so pay attention when designing.
Usage scenarios of observer mode
1. Associated behavior scenarios. It should be noted that the relationship behavior is detachable, not a "combined" relationship
2. Multi-level event triggering scenarios
3. Cross-system message exchange scenarios, such as message queue processing mechanism

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











PHP 8.4 brings several new features, security improvements, and performance improvements with healthy amounts of feature deprecations and removals. This guide explains how to install PHP 8.4 or upgrade to PHP 8.4 on Ubuntu, Debian, or their derivati

This tutorial demonstrates how to efficiently process XML documents using PHP. XML (eXtensible Markup Language) is a versatile text-based markup language designed for both human readability and machine parsing. It's commonly used for data storage an

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

A string is a sequence of characters, including letters, numbers, and symbols. This tutorial will learn how to calculate the number of vowels in a given string in PHP using different methods. The vowels in English are a, e, i, o, u, and they can be uppercase or lowercase. What is a vowel? Vowels are alphabetic characters that represent a specific pronunciation. There are five vowels in English, including uppercase and lowercase: a, e, i, o, u Example 1 Input: String = "Tutorialspoint" Output: 6 explain The vowels in the string "Tutorialspoint" are u, o, i, a, o, i. There are 6 yuan in total

What are the magic methods of PHP? PHP's magic methods include: 1.\_\_construct, used to initialize objects; 2.\_\_destruct, used to clean up resources; 3.\_\_call, handle non-existent method calls; 4.\_\_get, implement dynamic attribute access; 5.\_\_set, implement dynamic attribute settings. These methods are automatically called in certain situations, improving code flexibility and efficiency.

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

PHP is a scripting language widely used on the server side, especially suitable for web development. 1.PHP can embed HTML, process HTTP requests and responses, and supports a variety of databases. 2.PHP is used to generate dynamic web content, process form data, access databases, etc., with strong community support and open source resources. 3. PHP is an interpreted language, and the execution process includes lexical analysis, grammatical analysis, compilation and execution. 4.PHP can be combined with MySQL for advanced applications such as user registration systems. 5. When debugging PHP, you can use functions such as error_reporting() and var_dump(). 6. Optimize PHP code to use caching mechanisms, optimize database queries and use built-in functions. 7
