1. Definition des Beobachtermodus:
Der Beobachtermodus wird auch als Abonnement-Veröffentlichungsmodus bezeichnet, in dem ein Zielobjekt alle von ihm abhängigen Observer-Objekte verwaltet und Benachrichtigungen, wenn sich sein Zustand ändert, aktiv ausgibt. Dies wird normalerweise erreicht, indem die Methoden jedes Beobachters aufgerufen werden. Dieses Muster wird normalerweise in Ereignisverarbeitungssystemen verwendet.
1. Allgemeine Struktur des Beobachtermusters
Schauen wir uns zunächst die Beschreibung des Klassendiagramms des Beobachtermusters an:
Die Rollen des Beobachtermodus sind wie folgt:
Betreff (abstrakte Themenschnittstelle): Definiert eine Reihe von Operationen in der Observer -Liste in der Themenklasse, einschließlich Addition, Löschung, Benachrichtigung usw.
Konkretes Thema (spezifische Themenklasse):
Beobachter (Abstract Observer Interface): Definiert den Beobachter, Vorgänge zum Status der Themenklassen zu akzeptieren.
ConcreteObserver (spezifische Beobachterklasse): Implementiert Logik wie aktualisierte Themenklassenbenachrichtigungen durch die Observer -Schnittstelle.
Aus diesem Klassendiagramm können wir sehen, dass die Themenklasse eine Klassenliste beibehält, die die Observer -Schnittstelle implementiert. Die Themenklasse verwendet diese Liste, um eine Reihe von Ergänzungen, Löschungen und Änderungen des Beobachters durchzuführen. Die Beobachterklasse kann auch aktiv die Aktualisierungsmethode aufrufen, um die Status -Update -Informationen der Themenklasse zu verstehen.
Die obigen Klassendiagramme beschreiben nur die grundlegende Observer -Musteridee, und es gibt viele Mängel. Als Beobachter können Sie beispielsweise auch bestimmte Themen aktiv abonnieren usw. Die folgenden Beispiele nehmen einige Änderungen vor, um eine bestimmte Geschäftslogik anzuwenden.
2. Beispiel für Beobachtermodus
Wir erstellen einen Beobachter und eine Themenklasse, in der Beobachter Themen aktiv abonnieren oder absagen können. Die Kategorie der Themen wird von einem Themenmanager einheitlich verwaltet. Das Folgende ist ein Klassendiagramm:
Thema:
public interface Betreff {// Registrieren Sie ein Observer Public Void Register (Beobachterbeobachter); // einen Beobachter öffentlichen Leere entfernen (Beobachterbeobachter); // alle Beobachter public void musifyObServers () benachrichtigen; // Die Nachricht, die von der Themenklasse veröffentlicht wird, öffentliche String getMessage ();} ConcertSubject: öffentliche Klasse MySubject implementiert Betreff {private Liste <Beerver> Beobachter; privat booleschen änderte sich; private String -Nachricht; // Objektsperrung, verwendet, um die Beobachterliste private endgültiges Objekt mutex = new Object () zu aktualisieren; public mySubject () {Beobachter = new ArrayList <Beenserver> (); geändert = falsch; } @Override public void Register (Beobachter Observer) {if (observer == null) werfen neue nullpointerexception (); // zertifizieren nicht, um zu wiederholen, ob (! Beobachter.Contains (Observer)) Beobachter.Add (Beobachter); } @Override public void remove (Observer Observer) {Beobachter.Remove (Beobachter); } @Override public void musifyObServers () {// Templistliste <Beerver> tempobservers = null; synchronisiert (mutex) {if (! geändert) return; tempobservers = new ArrayList <> (this.observers); this.changed = false; } für (Beobachter obj: tempobservers) {obj.update (); }} // Themenklasse veröffentlicht eine neue Nachricht public void makechanged (String -Nachricht) {System.out.println ("Das Thema macht eine Änderung:" + meldung); this.message = message; this.changed = true; NotifyObServers (); } @Override public String getMessage () {return this.message; }}Wenn ConcertSubject ein Update erstellt, werden alle Beobachter in der Liste benachrichtigt, und die Beobachter -Update -Methode wird aufgerufen, um die Logik nach Erhalt der Benachrichtigung zu implementieren. Beachten Sie hier den Synchronisationsblock in BenachrichtigungObserver. Im Fall von Multi-Threading wird im Synchronisationsblock eine temporäre Liste verwendet, um die aktuelle Beobachterliste zu erhalten, um die Liste der Beobachter durch andere Threads bei der Veröffentlichung von Benachrichtigungen in der Themenklasse zu vermeiden und zu löschen.
Betreff: Themenklassenmanager
public class Betreffmanagement {// Ein Datensatzname - Map private map <string, Betreff> Subjektlist = new Hashmap <String, Betreff> (); public void addSubject (Zeichenfolge Name, Betreff) {Subjektlist.put (Name, Betreff); } public void addSubject (Betreff) {Subjektlist.put (Subjekt.getClass (). getName (), Subjekt); } public Subjekt getUbject (String -Betreff) {return subjektlist.get (Subjektname); } public void removeSubject (String -Name, Betreff) {} public void removeSubject (Subjekt) {} // Singleton private Subjektmanagement () {} öffentliches statisches Subjektmanagement getInstance () {return subjektmanagement.instance; } private statische Klasse Subjektmanagementinstanz {statische endgültige Subjektmanagementinstanz = new Subjektmanagement (); }}Der Zweck des Themenmanagers ist es, ein Instanzobjekt des Themas zu erhalten, wenn der Beobachter ein Thema abonniert.
Beobachter:
öffentliche Schnittstelle Beobachter {public void update (); public void setSubject (Subjekt);} concerteObserver: öffentliche Klasse Myobserver implementiert Observer {privates Thema; // Die Benachrichtigung von Meldungen von Concentrate Subjekt @Override public void update () {String message = subjekt.getMessage (); System.out.println ("From Subjekt" + Subjekt.getClass (). GetName () + "meldung:" + meldung); } @Override public void setSubject (Subjekt) {this.subject = Subjekt; } // subcirbe ein Thema public void abonnieren (String -Subjektname) {Subjektmanagement.getInstance (). } // Abonnieren Sie public void cancelsuBScribe (String -Betreff) {Subjektmanagement.getInstance (). Getubject (Subjektname) .Remove (this); }} Test: Wir sind abstrakte Fachklassen und Beobachter in Schriftsteller und Leser
public class beobachtest {private static mySubject Writer; @BeForeClass Public static void setupBeForeClass () löst Ausnahme aus {writer = new mySubject (); // einen Schriftsteller namens Linus Subjektmanagement.getInstance () addSubject ("Linus", Schriftsteller); } @Test public void test () {// Mehrere Leser myobserver reader1 = new Myobserver (); Myobserver reader2 = new myobserver (); Myobserver reader3 = new myobserver (); Reader1.Setsubject (Schriftsteller); Reader2.Setsubject (Schriftsteller); Reader3.Setsubject (Schriftsteller); Reader1.Subscribe ("Linus"); Reader2.Subscribe ("Linus"); Reader3.Subscribe ("Linus"); writer.makechanged ("Ich habe eine neue verändert"); Reader1.Update (); }}Das obige ist ein kleines Beispiel für das Beobachtermuster. Es ist ersichtlich, dass jede Themenklasse eine entsprechende Beobachterliste beibehalten muss. Hier können wir auf der Grundlage der abstrakten Ebene des spezifischen Themas weiter abstrakt werden und diese Sammlung in eine abstrakte Klasse einfügen, um eine Liste gemeinsam zu verwalten. Natürlich hängt der spezifische Betrieb von der tatsächlichen Geschäftslogik ab.
2. Zuhörer im Servlet
Lassen Sie uns über den Hörer in Servlet sprechen. Lassen Sie uns über eine andere Form des Beobachtermusters sprechen - das ereignisgesteuerte Modell. Wie die oben erwähnte Themenrolle des Observer-Musters umfasst das ereignisgesteuerte Modell Ereignisquellen, bestimmte Ereignisse, Zuhörer und bestimmte Zuhörer.
Hörer in Servlet ist ein typisches ereignisorientiertes Modell.
In JDK gibt es eine Reihe von ereignisorientierten Klassen, einschließlich einer einheitlichen Höreroberfläche und einer einheitlichen Ereignisquelle. Der Quellcode lautet wie folgt:
/*** Eine Tagging -Schnittstelle, die sich alle Event -Listener -Schnittstellen verlängern müssen. * @Since jdk1.1 */public interface eventListener {}Dies ist eine Flag -Schnittstelle, und die JDK stellt fest, dass alle Zuhörer diese Schnittstelle erben müssen.
public class EventObject implementiert java.io.serializable {private statische endgültige lange Serialversionuid = 5516075349620653480L; /*** Das Objekt, für das das Ereignis ursprünglich aufgetreten ist. */ geschützte transiente Objektquelle; /*** konstruiert ein Prototypereignis. * * @param Quelle das Objekt, auf dem das Ereignis ursprünglich aufgetreten ist. * @Exception illegalArgumentException Wenn Quelle null ist. */ public eventObject (Objektquelle) {if (source == null) werfen neue illegalArgumentException ("Null Source"); this.source = Quelle; } /*** Das Objekt, auf dem das Ereignis ursprünglich aufgetreten ist. * * @return das Objekt, auf dem das Ereignis ursprünglich aufgetreten ist. */ public Object gotsource () {return Source; } /*** Gibt eine String -Darstellung dieses EventObject zurück. * * @return eine String -Darstellung dieses EventObject. */ public String toString () {return getClass (). getName () + "[source =" + Quelle + "]"; }}EvenObject ist eine von JDK festgelegte einheitliche Ereignisquelle. Die EvenObject -Klasse definiert eine Ereignisquelle und eine GET -Methode, um die Ereignisquelle zu erhalten.
Analysieren wir den Betriebsprozess des Servlet -Hörers.
1. Die Komposition des Servlet -Hörers
Derzeit gibt es 6 Arten von Höreroberflächen für zwei Arten von Ereignissen in Servlets, wie in der folgenden Abbildung gezeigt:
Die spezifische Triggersituation ist wie folgt:
2. Ein spezifischer Listener -Auslöserprozess
Nehmen wir servletRequestattributelistener als Beispiel, um den ereignisgesteuerten Prozess hier zu analysieren.
Wenn HttpServletRequest die SetAttrilbute -Methode aufruft, wird dies zunächst org.apache.catalina.connector.Request#setAttrilbute -Methode genannt. Schauen wir uns den Quellcode an:
public void setAttribute (String -Name, Objektwert) {... // Der obige Logikcode wurde weggelassen // Hier wird der Hörer benachrichtigenAtTribUTaSadered (Name, Wert, OldValue); }Im Folgenden ist der Quellcode von NotifyAtTributaSesigned (String -Name, Objektwert, Objekt OldValue) aufgeführt.
private void musifyAttributaSsigned (String -Name, Objektwert, Objekt OldValue) {// Erhalten Sie das Instanzobjekt des Listeners in der WebApp von den Containerobjekt -Hörern [] = context. if (((Hörer == null) || (Hörer.length == 0)) {return; } boolean ersetzt = (oldValue! = null); // Verwandte Ereignisobjekte ServletRequestAttributeEvent Event = null; if (ersetzt) {event = new ServletRequestAttributeEvent (context.getServletContext (), getRequest (), Name, OldValue); } else {event = new ServletRequestAttributeEvent (context.getServletContext (), getRequest (), Name, Wert); } // Ruhe durch alle Hörerlisten und finden Sie den Hörer für das entsprechende Ereignis für (int i = 0; i <lousers.length; i ++) {if (! (Hörer [i] Instanz von ServletRequestattributelistener)) {Weiter; } // Die Listener -Methode rufen, um den Hörbetrieb ServletRequestAtRIBUTelistener Listener = (ServletRequestatTribUTelistener) Hörer [i] implementieren; try {if (ersetzt) {louser.attributerePlaced (Ereignis); } else {listener.attributeadded (Ereignis); }} catch (throwable t) {exceptionutils.handlethrowable (t); context.getLogger (). error (sm.getString ("coyoterequest.attributeEvent"), t); // Fehlerventil nimmt diese Ausnahme auf und zeigt sie auf Benutzerattribute an. }}}Das obige Beispiel zeigt deutlich, wie der ServletRequestattributelistener aufgerufen wird. Benutzer müssen nur die Listener -Schnittstelle implementieren. Zuhörer in Servlets decken fast Veranstaltungen ab, an denen Sie während des gesamten Lebenszyklus des Servlets interessiert sind. Die flexible Verwendung dieser Hörer kann das Programm flexibler machen.
3. umfassende Beispiele
Wenn Sie beispielsweise TVBs Polizei- und Gangster -Filme gesehen haben, werden Sie wissen, wie die Undercover funktioniert. Im Allgemeinen kann ein Polizist mehrere verdeckte Agenten haben, die sich in den Feind schleichen und sich nach Informationen erkundigen. Der Undercover -Agent arbeitet vollständig auf den Anweisungen seines Führers. Der Führer sagt, welcher Aktion er folgen muss. Wenn sich die Aktionszeit ändert, muss er die Zeit, die er mit der Aktion zusammenarbeitet, sofort ändern. Wenn der Führer zwei Undercover -Agenten schickt, um in den Feind einzudringen, entspricht der Führer einem abstrakten Thema. Inspektor Zhang San schickte zwei Undercover -Agenten Li Si und Wang Wang Wu. Zhang San entspricht einem bestimmten Thema, und der Undercover -Agent entspricht einem abstrakten Beobachter. Diese beiden Undercover -Wirkstoffe sind Li Si und Wang Wu, die spezifische Beobachter sind. Die Aktion der Untersuchung entspricht dem Beobachter, der das Thema registriert. Dann lautet dieses Klassendiagramm wie folgt:
Verwenden der Java -API, um die Codebeschreibung wie folgt zu implementieren:
Paketbeobachter; importieren java.util.list; Import Java.util.Observable; Import Java.util.Observable; / ***Beschreibung: Polizei Zhang San*/ Public Class Police erweitert die beobachtbare {private String -Zeit; Public Police (Liste <Observer> Liste) {Super (); für (Beobachter O: Liste) {Addobserver (o); }} public void Change (String -Zeit) {this.time = time; setChanged (); notifyObservers (this.time); }} Paketbeobachter; Import Java.util.Observable; import Java.util.observer; / ** *Beschreibung: Undercover a */ öffentliche Klasse Undercovera implementiert Observer {private String -Zeit; @Override public void update (beobachtbar O, Objekt arg) {time = (string) arg; System.out.println ("Eine Nachricht erhalten, und die Aktionszeit lautet:"+Zeit); }} Paketbeobachter; Import Java.util.Observable; import Java.util.observer; / ** *Beschreibung: Undercover B */ Public Class Undercoverb implementiert Observer {private String -Zeit; @Override public void update (beobachtbar O, Objekt arg) {time = (string) arg; System.out.println ("Enthüllung B erhielt eine Nachricht, und die Aktionszeit war:"+Zeit); }} Paketbeobachter; Import Java.util.ArrayList; importieren java.util.list; import Java.util.observer; / ***Beschreibung: Test*/ Public Class Client {/ ***@param args*/ public static void main (String [] args) {Undercovera o1 = new Undercovera (); Undercoverb O2 = neuer Undercoverb (); Liste <Beerver> list = new ArrayList <> (); list.add (O1); list.add (o2); Polizei Betreff = neue Polizei (Liste); Betreff.Change ("02:25"); System.out.println ("========================= weil die Informationen ausgesetzt sind, ist die Aktionszeit Fortgeschrittene ============================================================================== ch. TEST RUN ERGEBNISSE:
Undercover B hat die Nachricht erhalten, und die Aktionszeit ist: 02:25 Undercover A empfangen die Nachricht, und die Aktionszeit lautet: 02:25 ============== aufgrund der Belichtung der Nachricht, die Aktionszeit ist im Voraus.
4. Zusammenfassung
Das Beobachtermuster definiert eine Eins-zu-Viele-Beziehung zwischen Objekten. Wenn sich der Zustand eines Objekts (der Beobachter) ändert, werden die von ihm abhängigen Objekte benachrichtigt. Es kann angewendet werden, um in solchen Geschäftsszenarien zu veröffentlichen, und das update-update-update.
Der Beobachter verwendet eine lose Kupplungsmethode. Der Beobachter kennt die Details des Beobachters nicht, weiß jedoch nur, dass der Beobachter die Schnittstelle implementiert hat.
Das ereignisgesteuerte Modell ist flexibler, zahlt aber auch die Kosten für die Systemkomplexität, da wir einen Hörer und Ereignis für jede Ereignisquelle anpassen müssen, was die Belastung des Systems erhöht.
Der Kern des Beobachtermodells besteht darin, zunächst die Rolle zu unterscheiden und den Beobachter und den Beobachter zu positionieren, und sie sind eine viel- und eins-Beziehung. Der Schlüssel zur Implementierung besteht darin, eine Verbindung zwischen dem Beobachter und dem Beobachter herzustellen. Beispielsweise gibt es in der Beobachterklasse, mit der der Beobachter gespeichert wird, und alle Beobachter müssen benachrichtigt werden, wenn sich das erkannte Ding ändert. Im Konstruktor des Beobachters wird er vom Beobachter übergeben und registriert sich auch in der Liste der Beobachter, die dem Beobachter gehören, dh in der Liste der Beobachter.
1. Vorteile des Beobachtermodus:
(1) Abstrakte Themen beruhen nur auf abstrakte Beobachter
2. Nachteile des Beobachtermodus:
(1) Wenn ein Thema von einer großen Anzahl von Beobachtern registriert ist, kostet es einen höheren Preis, um alle Beobachter zu benachrichtigen (2) Wenn die Antwortmethode einiger Beobachter blockiert ist, wird der gesamte Benachrichtigungsprozess blockiert und andere Beobachter können nicht rechtzeitig benachrichtigt werden.