1. Définition du mode observateur:
Le mode observateur est également appelé mode abonnement-publique, dans lequel un objet cible gère tous les objets d'observateurs en dépendant et émet activement des notifications lorsque son état change. Ceci est généralement réalisé en appelant les méthodes de chaque observateur. Ce modèle est généralement utilisé dans les systèmes de traitement d'événements.
1. Structure générale du modèle d'observateur
Tout d'abord, jetons un coup d'œil à la description du diagramme de classe du modèle d'observateur:
Les rôles du mode observateur sont les suivants:
Sujet (Résumé Interface du sujet): définit une série d'opérations sur la liste des observateurs dans la classe de thème, y compris l'ajout, la suppression, la notification, etc.
Sujet concret (classe de sujet spécifique):
Observer (Abstract Observer Interface): définit l'observateur pour accepter les opérations sur l'état de mise à jour de la classe de sujet.
ConcreteObserver (Classe d'observateurs spécifiques): implémente la logique telle que les notifications de classe de thème de mise à jour par l'interface d'observateur.
À partir de ce diagramme de classe, nous pouvons voir que la classe de thème maintient une liste de classe qui implémente l'interface d'observateur. La classe de thème utilise cette liste pour effectuer une série d'ajouts, de suppressions et de modifications sur l'observateur. La classe Observer peut également appeler activement la méthode de mise à jour pour comprendre les informations de mise à jour de l'état de la classe de thème.
Les diagrammes de classe ci-dessus ne décrivent que l'idée de base de l'observateur de base, et il existe de nombreuses lacunes. Par exemple, en tant qu'observateur, vous pouvez également vous abonner activement à certains sujets, etc. Les exemples suivants apporteront des modifications pour appliquer une logique métier spécifique.
2. Exemple de mode observateur
Nous construisons un observateur et une classe de sujet, où les observateurs peuvent s'abonner activement à ou annuler des sujets. La catégorie de thème est uniformément gérée par un gestionnaire de thème. Ce qui suit est un diagramme de classe:
Sujet:
Sujet de l'interface publique {// Enregistrer un registre de void public observateur (Observer Observer); // supprimer un observateur public vide supprimer (observateur observateur); // informer tous les observateurs publics void notifyObservers (); // Obtenez le message publié par la classe de sujets public String GetMessage ();} ConcertesUbject: public class MySubject implémente le sujet {private list <Observer> observateurs; Boolean privé a changé; Message de chaîne privé; // verrouillage d'objet, utilisé pour mettre à jour de manière synchrone la liste d'observateurs Final Object Mutex = new Object (); public mySubject () {observateurs = new ArrayList <Bervever> (); changé = false; } @Override public void Register (Observer Observer) {if (Observer == NULL) lance un nouveau nullPointerException (); // certifier de ne pas répéter si (! Observeurs.Contains (Observer)) Observeurs.Add (Observer); } @Override public void reous (Observer Observer) {Observeurs.Remove (Observer); } @Override public void notifyObservers () {// Temps List List <Bserver> tempObservers = null; synchronisé (mutex) {if (! changé) return; tempoBServers = new ArrayList <> (this.observers); this.changed = false; } pour (Observer Obj: tempObservers) {obj.update (); }} // La classe de thème publie un nouveau message public void makechanged (message de chaîne) {System.out.println ("Le sujet fait un changement:" + message); this.Message = message; this.changed = true; notifyObservers (); } @Override public String getMessage () {return this.Message; }}Lorsque Concertesubject fait une mise à jour, tous les observateurs de la liste sont informés et la méthode de mise à jour des observateurs est appelée pour implémenter la logique après avoir reçu la notification. Notez le bloc de synchronisation dans NotifyObservers ici. Dans le cas du multi-threading, afin d'éviter d'ajouter et de supprimer la liste des observateurs par d'autres threads lors de la publication de notifications dans la classe de sujet, une liste temporaire est utilisée dans le bloc de synchronisation pour obtenir la liste des observateurs actuelle.
Subjette: Gestionnaire de classe de thème
classe publique SubjectManagement {// un nom d'enregistrement - Map Private Map <String, SubditionList = new HashMap <String, Subject> (); public void AddSubject (nom de chaîne, sujet sujet) {sujectList.put (nom, sujet); } public void AddSubject (sujet sujet) {sujetList.put (sujet.GetClass (). getName (), sujet); } public sujet getSubject (String sujetName) {return sujectList.get (sujet); } public void removeSubject (nom de la chaîne, sujet sujet) {} public void removeSubject (sujet sujet) {} // singleton private subiterManagement () {} public static submencengion gentance () {return subitermanagement.instance; } classe statique privée SubjectManagementInstance {instance finale statique FinalManagement = new SubterManagement (); }}Le but du gestionnaire de sujets est d'obtenir un objet d'instance du sujet lorsque l'observateur s'abonne à un sujet.
Observateur:
Public Interface Observer {public void Update (); public void setSubject (sujet sujet);} ConcerTeOrtServer: la classe publique MyoBserver implémente l'observateur {Sujet privé; // Obtenez le message de notification de Concentrate Subject @Override public void Update () {String Message = sujet.GetMessage (); System.out.println ("From Subject" + sujet.getClass (). GetName () + "Message:" + Message); } @Override public void setSubject (sujet sujet) {this.subject = sujet; } // sous-Cirbe Certains sujets publics subid abribus (String SubjectName) {SubterManagement.getInstance (). GetSubject (SubterName) .Register (this); } // annuler l'abonnement public void cancelsubscribe (String sujectName) {sujectManagement.getInstance (). GetSubject (sujet) .Remove (this); }} Test: nous abstraions des classes de matières et des observateurs dans les écrivains et les lecteurs
classe publique ObserverTest {écrivain privé MySubject statique; @BeForeclass public static void setupBeForClass () lève une exception {écrivain = new mySubject (); // Ajouter un écrivain nommé linus subitermanagement.getInstance (). AddSubject ("linus", écrivain); } @Test public void test () {// définir plusieurs lecteurs MyoBserver Reader1 = new myoBserver (); MyoBserver Reader2 = new myoBserver (); MyoBserver Reader3 = new myoBserver (); Reader1.SetSubject (écrivain); Reader2.SetSubject (écrivain); Reader3.SetSubject (écrivain); Reader1.Subscribe ("Linus"); Reader2.Subscribe ("Linus"); Reader3.Subscribe ("linus"); écrivain.makechanged ("J'ai un nouveau changement"); Reader1.update (); }}Ce qui précède est un petit exemple du motif d'observateur. On peut voir que chaque classe de sujet doit maintenir une liste d'observateurs correspondante. Ici, nous pouvons davantage abstraits sur la base du niveau abstrait du sujet spécifique, mettre ce rassemblement dans une classe abstraite pour maintenir conjointement une liste. Bien sûr, l'opération spécifique dépend de la logique commerciale réelle.
2. Écouteur en servlet
Parlons de l'auditeur dans Servlet, parlons d'une autre forme du modèle d'observateur - le modèle axé sur l'événement. Comme le rôle thème du modèle d'observateur mentionné ci-dessus, le modèle axé sur l'événement comprend des sources d'événements, des événements spécifiques, des auditeurs et des auditeurs spécifiques.
L'auditeur de Servlet est un modèle typique d'événements.
Il existe un ensemble de classes axées sur des événements dans JDK, y compris une interface d'écoute unifiée et une source d'événements unifiée. Le code source est le suivant:
/ ** * Une interface de balisage que toutes les interfaces d'écoute d'événements doivent étendre. * @Since jdk1.1 * / interface publique EventListener {}Il s'agit d'une interface de drapeau, et le JDK stipule que tous les auditeurs doivent hériter de cette interface.
classe publique EventObject implémente Java.io.Serializable {private static final long SerialVersionUID = 5516075349620653480L; / ** * L'objet sur lequel l'événement s'est produit initialement. * / source d'objet transitoire protégé; / ** * Construit un événement prototype. * * @param Source l'objet sur lequel l'événement s'est produit initialement. * @Exception illégalArgumentException si la source est nul. * / public EventObject (objet Source) {if (source == null) lance un nouveau IllégalArgumentException ("Null Source"); this.source = source; } / ** * L'objet sur lequel l'événement s'est produit initialement. * * @return l'objet sur lequel l'événement s'est produit initialement. * / public objet getSource () {return source; } / ** * Renvoie une représentation de chaîne de ce événementObject. * * @return a une représentation de chaîne de cet événement. * / public String toString () {return getClass (). getName () + "[source =" + source + "]"; }}MêmeObject est une source d'événements unifiée spécifiée par JDK. La classe MELINOBject définit une source d'événement et une méthode GET pour obtenir la source d'événement.
Analysons le processus de fonctionnement de l'auditeur de servlet.
1. La composition de l'auditeur du servlet
Actuellement, il existe 6 types d'interfaces d'écoute pour deux types d'événements dans les servlets, comme le montre la figure ci-dessous:
La situation de déclenchement spécifique est la suivante:
2. Un processus de déclenchement de l'auditeur spécifique
Prenons un exemple de servletRequestAtTrributeListener pour analyser le processus axé sur les événements ici.
Tout d'abord, lorsque HttpServletRequest appelle la méthode setAttrilBute, elle est en fait appelée org.apache.catalina.connector.request # setAttrilBute Méthode. Jetons un coup d'œil à son code source:
public void setAttribute (nom de chaîne, valeur de l'objet) {... // Le code logique ci-dessus a été omis // Ici, l'écouteur est notifyAtTributEassigned (nom, valeur, oldvalue); }Ce qui suit est le code source de NotifyAtTributEASIGNED (nom de chaîne, valeur de l'objet, objet OldValue)
private void notifyAttributeASsigned (nom de chaîne, valeur d'objet, objet OldValue) {// Obtenez l'objet d'instance de l'écouteur défini dans le WebApp à partir des écouteurs d'objets de conteneur [] = context.getApplicationEventListeners (); if ((écouteurs == null) || (écouteurs.length == 0)) {return; } boolean remplacé = (oldValue! = null); // Créer un objet d'événement connexe ServLetRequestAttributeEvent Event = NULL; if (remplacé) {event = new ServLetRequestAttributeEvent (context.getServletContext (), getRequest (), name, oldvalue); } else {event = new ServLetRequestAtTrributeEvent (context.getServletContext (), getRequest (), nom, valeur); } // Tranquility via toutes les listes d'auditeurs et trouvez l'écouteur de l'événement correspondant pour (int i = 0; i <écouteurs.length; i ++) {if (! (Écouteurs [i] instanceof servLetRequestAttutLeListener)) {continue; } // Appel de la méthode de l'écoute pour implémenter l'opération d'écoute ServLetRequestAtTrutIleListERner auditeur = (servLetRequestAtTtRutLeListener) Écouteurs [i]; essayez {if (remplacé) {écouteur.AttributeReplace (événement); } else {écouteur.AttributeAdDed (événement); }} catch (Throwable T) {exceptionUtils.handleThrowable (t); context.getLogger (). Error (sm.getString ("coyoteRequest.attributeevent"), t); // Valve d'erreur ramassera cette exception et l'affichera à l'utilisateur Attributes.put (requestdispatcher.error_exception, t); }}}L'exemple ci-dessus montre clairement comment le servletRequestAttraTributleListener est appelé. Les utilisateurs n'ont qu'à implémenter l'interface de l'écoute. Les auditeurs des servlets couvrent presque les événements qui vous intéressent tout au long du cycle de vie du servlet. L'utilisation flexible de ces auditeurs peut rendre le programme plus flexible.
3. Exemples complets
Par exemple, si vous avez regardé les films de police et de gangster de TVB, vous saurez comment le fonctionnement de l'infiltration. Généralement, un policier peut avoir plusieurs agents infiltrés qui se faufilent dans l'ennemi et se renseignent sur les informations. L'agent d'infiltration travaille entièrement sur les instructions de son chef. Le leader dit quelle action il doit suivre. Si le temps d'action change, il doit immédiatement changer le temps qu'il coopère avec l'action. Si le leader envoie deux agents infiltrés pour envahir l'ennemi, le leader est équivalent à un thème abstrait. L'inspecteur Zhang San a envoyé deux agents d'infiltration Li Si et Wan Wang Wu. Zhang SAN équivaut à un thème spécifique, et l'agent d'infiltration est équivalent à un observateur abstrait. Ces deux agents infiltrés sont Li Si et Wang Wu, qui sont des observateurs spécifiques. L'action de l'enquête est équivalente à l'observateur enregistrant le sujet. Ensuite, ce diagramme de classe est le suivant:
Utilisation de l'API Java pour implémenter la description du code comme suit:
Package Observer; Importer java.util.list; import java.util.observable; import java.util.observable; / ** * Description: Police Zhang San * / classe publique La police étend observable {temps de chaîne privée; Police publique (Liste <Observer> Liste) {Super (); pour (Observer O: list) {addObserver (o); }} public void change (String time) {this.time = time; setChanged (); notifyObservers (this.time); }} Package Observer; import java.util.observable; import java.util.observer; / ** * Description: Undercover a * / public class Undercovera implémente l'observateur {time de chaîne privée; @Override public void Update (observable o, objet arg) {time = (string) arg; System.out.println ("Découvrir un message a reçu un message, et le temps d'action est:" + heure); }} Package Observer; import java.util.observable; import java.util.observer; / ** * Description: Undercover b * / public class Undercoverb implémente l'observateur {Temps de chaîne privé; @Override public void Update (observable o, objet arg) {time = (string) arg; System.out.println ("Découvrir B a reçu un message, et le temps d'action était:" + heure); }} Package Observer; import java.util.arraylist; Importer java.util.list; import java.util.observer; / ** * Description: Test * / public class Client {/ ** * @param args * / public static void main (String [] args) {Undercovera o1 = new Undercovera (); Undercoverb o2 = nouveau UndercoverB (); List <Observer> list = new ArrayList <> (); list.add (o1); list.add (o2); Sujet de la police = nouvelle police (liste); sujet.change ("02:25"); System.out.println ("======================= En raison de l'exposition des informations, le temps d'action est Advanced ================================================================================= Résultats des essais:
Undercover b a reçu le message, et le temps d'action est: 02:25 Undercover a reçu le message, et le temps d'action est: 02:25 ==============. En raison de l'exposition du message, le temps d'action est à l'avance ============ Undercover b a reçu le message, et le temps d'action est: 01:05 Undercover a reçu le message, et le temps d'action est: 01:05 Undercover R a reçu le message, et le temps d'action est: 01:05 Undercover R a reçu le message, et le temps d'action est: 01:05 Undercover R a reçu le message, et le temps d'action est: 01:05 Undercover R a reçu le message, et le temps d'action est: 01:05 Undercover R a reçu le message, et le temps d'action est: 01:05 Undercover R a reçu le message, et le temps d'action est: 01:05 Undercover R a reçu le message et le temps d'action est: 01:05
4. Résumé
Le modèle d'observateur définit une relation un-à-plusieurs entre les objets. Lorsque l'état d'un objet (l'observateur) change, les objets qui en dépendent seront informés. Il peut être appliqué à la publication de publication et à la mise à jour de mise à jour dans de tels scénarios commerciaux.
L'observateur utilise une méthode de couplage lâche. L'observateur ne connaît pas les détails de l'observateur, mais sait seulement que l'observateur a implémenté l'interface.
Le modèle axé sur les événements est plus flexible, mais il paie également le coût de la complexité du système, car nous devons personnaliser un auditeur et un événement pour chaque source d'événement, ce qui augmentera le fardeau du système.
Le noyau du modèle d'observateur est de distinguer d'abord le rôle et la position de l'observateur et de l'observateur, et ils sont une relation plusieurs à un. La clé de la mise en œuvre est d'établir un lien entre l'observateur et l'observateur. Par exemple, il y a un ensemble dans la classe d'observateurs qui est utilisé pour stocker l'observateur, et tous les observateurs doivent être informés lorsque la chose détectée change. Dans le constructeur de l'observateur, il sera transmis par l'observateur et s'inscrira également dans la liste des observateurs appartenant à l'observateur, c'est-à-dire la liste des observateurs.
1. Avantages du mode observateur:
(1) Les thèmes abstraits ne reposent que sur les observateurs abstraits (2) le mode observateur prend en charge la communication de diffusion (3) le mode observateur sépare la couche de génération d'informations et la couche de réponse
2. Inconvénients du mode observateur:
(1) Si un sujet est enregistré par un grand nombre d'observateurs, il coûtera un prix plus élevé pour informer tous les observateurs (2) Si la méthode de réponse de certains observateurs est bloquée, l'ensemble du processus de notification sera bloqué et que d'autres observateurs ne peuvent pas être informés dans le temps.