Heim  >  Artikel  >  Backend-Entwicklung  >  Beobachtermuster, bei dem Wände Ohren haben

Beobachtermuster, bei dem Wände Ohren haben

巴扎黑
巴扎黑Original
2016-11-12 13:56:281423Durchsuche

Jeder muss sich zuvor beim System angemeldet haben, um die Anmeldung erfolgreich durchzuführen. Wenn bei der Anmeldung ein Fehler auftritt, sollte das Sicherheitssystem den Fehler aufzeichnen Das E-Mail-System sollte auch relevante E-Mails an das Management-Mitglied senden. Dies ist so, als ob das Anmeldesystem von vielen Leuten überwacht wird. Sobald es Probleme gibt, werden andere Systeme sofort davon erfahren. Versuchen Sie dann, den Beobachtermodus zu verwenden:

Beobachtermuster, bei dem Wände Ohren haben
Ein sehr einfacher Modus, der Implementierungscode:

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(&#39;XXX&#39;,&#39;XXX&#39;,&#39;127.0.0.1&#39;);  
?>


Ergebnis ausführen, wenn ein Fehler auftritt:

SecurityMonitor: XXX konnte sich nicht bei 127.0.0.1 anmelden [Fertig in 0,1 s]

Sie können das sehen login-Objekt im Code Fügen Sie aktiv die SecurityMonitor-Objektbeobachtung hinzu. Um Login::getStatus() aufzurufen, muss die SecurityMonitor-Klasse auf diese Weise weitere Informationen kennen. Obwohl der Aufruf für ein ObServable-Objekt erfolgt, gibt es keine Garantie dafür, dass das Objekt auch ein Login-Objekt ist. Um dieses Problem zu lösen, gibt es einen Weg: Halten Sie die ObServable-Schnittstelle zeitweise generisch, und die ObServer-Klasse ist dafür verantwortlich, sicherzustellen, dass ihre Körper den richtigen Typ haben. Sie können sich sogar selbst zum Thema hinzufügen. Das Klassendiagramm lautet wie folgt:

Beobachtermuster, bei dem Wände Ohren haben
Der Implementierungscode lautet wie folgt:

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( &#39;XXX&#39;, &#39;XXX&#39;, &#39;127.0.0.1&#39; );  
?>

Das laufende Ergebnis ist das gleiche wie das obige Beispiel

in Nach PHP5 bietet die integrierte SPL-Erweiterung native Unterstützung für das Beobachtermuster. Nachdem Sie das obige Beispiel durch SPL verbessert haben:

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( &#39;XXX&#39;, &#39;XXX&#39;, &#39;127.0.0.1&#39; );  
?>

Der Code wurde geschrieben, aber Sie müssen noch einige Theorien verstehen.

Definition des Beobachtermusters

Definieren Sie eine Eins-zu-viele-Abhängigkeitsbeziehung zwischen Objekten, sodass jedes Mal, wenn ein Objekt seinen Zustand ändert, alle davon abhängigen Objekte benachrichtigt werden und automatisch erneuert werden. Das Beobachtermuster besteht aus vier Rollen:

1. Beobachteter Beobachter

definiert die Verantwortlichkeiten, die der Beobachter umsetzen muss, und es muss in der Lage sein, Beobachter dynamisch hinzuzufügen und zu löschen. Im Allgemeinen handelt es sich um eine abstrakte Klasse oder eine Implementierungsklasse, die nur die Verantwortlichkeiten erfüllt, die als Beobachter implementiert werden müssen, Beobachter verwaltet und Beobachter weitergibt.

2. Beobachter

Nach Erhalt der Nachricht führt der Beobachter einen Aktualisierungsvorgang durch und verarbeitet die empfangenen Informationen.

3. Der spezifische Beobachter von ConcreteSubject

definiert die eigene Geschäftslogik des Beobachters und definiert auch, über welche Ereignisse benachrichtigt werden soll.

4. ConcreteObserver-spezifische Beobachter

Jede Beobachtung hat eine andere Verarbeitungsreaktion nach dem Empfang der Nachricht, und jeder Beobachter hat seine eigene Verarbeitungslogik.

Vorteile des Beobachtermusters

1. Es gibt eine abstrakte Kopplung zwischen dem Beobachter und dem Beobachteten

Bei diesem Design spielt es keine Rolle, ob der Beobachter oder das Beobachtete hinzugefügt wird Es ist sehr einfach zu erweitern und die Definition von Abstraktionsebenen wurde in Java und PHP implementiert, was die Systemerweiterung noch komfortabler macht.

2. Richten Sie einen Auslösemechanismus ein

Nach dem Prinzip der Einzelverantwortung hat jede Klasse eine einzige Verantwortung. Wie kann man also jede einzelne Verantwortung in einer komplexen logischen Beziehung in der realen Welt verbinden? Das Beobachtermuster kann hier die Kettenform perfekt implementieren

Nachteile des Beobachtermusters

Das Beobachtermuster muss Entwicklungseffizienz und Betriebseffizienz berücksichtigen ist ein Problem. Bei einem Beobachter und mehreren Beobachtern wird die Entwicklung und das Debuggen komplizierter. Darüber hinaus werden Nachrichtenbenachrichtigungen nacheinander ausgeführt. Wenn ein Beobachter hängen bleibt, wirkt sich dies auf die Gesamtausführungseffizienz aus. In diesem Fall kommen im Allgemeinen asynchrone Methoden in Betracht. Noch besorgniserregender ist die Effizienz der mehrstufigen Auslösung. Achten Sie daher beim Entwurf darauf.

Nutzungsszenarien des Beobachtermodus

1. Es ist zu beachten, dass das Beziehungsverhalten trennbar und keine „kombinierte“ Beziehung ist

2. Mehrstufige Ereignisauslöseszenarien

3. Systemübergreifende Nachrichtenaustauschszenarien, z. B. Nachricht Warteschlangenverarbeitungsmechanismus


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn