I. The definition OF the Observer Model (OBSERVER):
The Observer pattern is also known as the subscription-publish pattern, in which a target object manages all the observer objects that are dependent on it and actively notifies itself when its state changes. This is usually done by calling the methods provided by the various observers. This pattern is often used for event-handling systems.
1, the general structure of the observer model
First look at the class diagram description of the Observer pattern:
The role of the observer pattern is as follows:
Subject (Abstract Theme Interface): Defines a series of actions on the observer list in the subject class, including additions, deletions, notifications, and so on.
Concrete Subject (Specific topic Class):
Observer (Abstract Observer Interface): Defines the observer's acceptance action on the subject class update state.
Concreteobserver (Specific Observer Class): The realization of the Observer interface to update the subject class notification and other logic.
As you can see from this class diagram, a list of classes that implement the Observer interface is maintained in the subject class, and the subject class makes a series of additions and deletions to the viewer through this list. The Observer class can also actively invoke the Update method to understand the status update information for the subject class.
The above class diagram describes only the basic observer mode of thought, there are many deficiencies. For example, as observers can also actively subscribe to a certain type of topic. The following example will make some changes to apply the specific business logic.
2. Example of observer mode
We build an observer and subject class, and the observer can actively subscribe to the topic or cancel the topic. Subject-Class unification is managed by a subject manager. The class diagram is given below:
Subject:
Public interface Subject {//register a Observer public void register (Observer Observer);
Remove a Observer public void remove (Observer Observer);
Notify all observers of the public void Notifyobservers ();
Gets the message public String getMessage () to be published by the subject class.
} Concertesubject:public class Mysubject implements Subject {private list<observer> observers;
private Boolean changed;
Private String message;
Object lock, for synchronizing update Observer list private final Object mutex = new Object ();
Public Mysubject () {observers = new arraylist<observer> ();
Changed = FALSE; @Override public void Register (Observer Observer) {if (Observer = null) throw new NullPointerException ()
;
Guaranteed not to repeat if (!OBSERVERS.CONTAINS (Observer)) OBSERVERS.ADD (Observer);
@Override public void Remove (Observer Observer) {observers.remove (Observer);
@Override public void Notifyobservers () {//Temp list list<observer> tempobservers = null;
Synchronized (mutex) { if (!changed) return;
Tempobservers = new arraylist<> (this.observers);
This.changed = false;
for (Observer obj:tempobservers) {obj.update (); }//Subject class publishing new message public void makechanged (String message) {System.out.println ("The Subject Make a change:" + mess
Age);
this.message = message;
This.changed = true;
Notifyobservers ();
@Override public String GetMessage () {return this.message;
}
}
When Concertesubject makes an update, it notifies all the observers in the list and calls the Observer Update method to implement the logic after the notification is received. Notice here the sync block in the notifyobservers. In the case of multithreading, in order to avoid the topic class release notification, other threads to the Observer list additions and deletions operations, synchronization block with a temporary list to get the current list of observers.
Subjectmanagement: Theme class Manager
public class Subjectmanagement {
//a record name-theme class Map
private map<string, subject> subjectlist = new HashMap <string, subject> ();
public void Addsubject (String name, Subject Subject) {
subjectlist.put (name, Subject);
}
public void Addsubject (Subject Subject) {
subjectlist.put (Subject.getclass (). GetName (), Subject);
Public Subject Getsubject (String subjectname) {return
subjectlist.get (subjectname);
}
public void Removesubject (String name, Subject Subject) {
} public
void Removesubject (Subject Subject) {
//singleton
Private subjectmanagement () {} public
static Subjectmanagement getinstance () {
return subjectmanagementinstance.instance;
}
private static class Subjectmanagementinstance {
static final subjectmanagement instance = new Subjectmanagement ();
}
}
The purpose of the Theme class manager is to get an instance object for this topic when the Observer subscribes to a topic.
Observer:
Public interface Observer {public
void Update ();
public void Setsubject (Subject Subject);
}
Concerteobserver: Public
class Myobserver implements Observer {
private Subject Subject;
Get the notify message from concentrate Subject
@Override public
Void Update () {
String message = Subject. GetMessage ();
System.out.println ("from Subject" + Subject.getclass (). GetName ()
+ ' message: ' + message);
}
@Override public
void Setsubject (Subject Subject) {
this.subject = Subject;
}
Subcirbe some Subject public
void Subscribe (String subjectname) {
subjectmanagement.getinstance (). Getsubject (subjectname). Register (this);
Cancel Subcribe public
void Cancelsubcribe (String subjectname) {
subjectmanagement.getinstance (). Getsubject (subjectname). Remove (this);
}
Test: We abstract the subject class and the observer into the writer and the reader
public class Observertest {
private static mysubject writer;
@BeforeClass public
static void Setupbeforeclass () throws Exception {
writer = new Mysubject ();
Add a writer named Linus
subjectmanagement.getinstance (). Addsubject ("Linus", writer);
@Test public
void Test () {
//define several readers
myobserver reader1 = new Myobserver ();
Myobserver reader2 = new Myobserver ();
Myobserver Reader3 = new Myobserver ();
Reader1.setsubject (writer);
Reader2.setsubject (writer);
Reader3.setsubject (writer);
Reader1.subscribe ("Linus");
Reader2.subscribe ("Linus");
Reader3.subscribe ("Linus");
Writer.makechanged ("I have a new Changed");
Reader1.update ();
}
The above is a small example of the observer pattern. It can be seen that each topic class maintains a corresponding list of observers, which can be further abstracted from the abstract level of the specific topic and put into an abstract class to implement to jointly maintain a list, of course, depending on the actual business logic.
Second, the listener in the servlet
Before talking about the listener in the servlet, let's talk about another form of the observer pattern-the event-driven model. As with the subject role of the observer pattern mentioned above, the event-driven model includes an event source, a specific event, a listener, and a specific listener.
The listener in the servlet is a typical event-driven model.
JDK has a set of event-driven classes, including a unified listener interface and a unified source of events, the source code is as follows:
/**
* A tagging interface The all event listener interfaces must.
* @since JDK1.1 * * * public
interface EventListener {
}
This is a flag interface that the JDK requires that all listeners must inherit this interface.
public class EventObject implements java.io.Serializable {private static final long Serialversionuid = 551607534962065
3480L;
/** * The object on which the Event initially occurred.
* * protected transient Object source;
/** * Constructs a prototypical Event.
* @param source the object on which the Event initially occurred.
* @exception illegalargumentexception if source is null.
*/Public EventObject (Object source) {if (source = = null) throw new IllegalArgumentException ("null source");
This.source = source;
}/** * The object on which the Event initially occurred.
* * @return The object on which the Event initially occurred.
*/Public Object GetSource () {return source;
}/** * Returns a String representation of this eventobject.
* * @return A String representation of this eventobject.
*/Public String toString () {return getclass () getName () + "[source=" + source + "]";
}
}
Evenobject is a unified source of events that the JDK provides us with. The Evenobject class defines an event source and a Get method that gets the event source.
The following is an analysis of the servlet listener running process.
1, the composition of the Servlet listener
Currently, there are 6 types of listener interfaces for two types of events in the servlet, as shown in the following illustration:
The following table is the specific triggering scenario:
2, a specific listener trigger process
Let's take servletrequestattributelistener as an example to analyze the event-driven process here.
First in a servlet, when HttpServletRequest calls the Setattrilbute method, it is actually the Org.apache.catalina.connector.request#setattrilbute method that is invoked. Let's look at its source code:
public void setattribute (String name, Object value) {
...
The above logical code has been omitted
//Here is the notification listener
notifyattributeassigned (name, value, OldValue);
}
The following is the source code for notifyattributeassigned (String name, object value, Object OldValue)
private void notifyattributeassigned (String name, object value, Object OldValue) {//From the container gets the listener that is defined in the WebApp
Example Object listeners[] = Context.getapplicationeventlisteners (); if ((listeners = null) | | (listeners.length = 0))
{return;
Boolean replaced = (OldValue!= null);
Create a related event object servletrequestattributeevent event = null; if (replaced) {event = new Servletrequestattributeevent (Context.getservletcontext (), Getrequest (), name,
OldValue); else {event = new Servletrequestattributeevent (Context.getservletcontext (), Getrequest (), name, value)
; //traverse the list of all listeners, find the listener for the corresponding event for (int i = 0; i < listeners.length; i++) {if (!) (
Listeners[i] instanceof Servletrequestattributelistener)) {continue; //Call listener method to implement listener operation Servletrequestattributelistener Listener = (servletrequestattributelistener) List
Eners[i];
try {if (replaced) {Listener.attributereplaced (event);
else {listener.attributeadded (event);
A catch (Throwable t) {exceptionutils.handlethrowable (t);
Context.getlogger (). Error (Sm.getstring ("coyoterequest.attributeevent"), T); Error valve'll pick this exception up and display it to user attributes.put (requestdispatcher.error_exception
, t);
}
}
}
The above example clearly shows how the Servletrequestattributelistener is invoked. Users only need to implement the listener interface on the line. The listener in the servlet almost covers events of interest to the servlet throughout its lifecycle, and flexible use of these listenser can make the program more flexible.
III. Integrated Examples
For example, if you've seen TVB's robbers, you know how undercover works. Generally a police officer may have several undercover, sneak into the enemy inside, to pry information, undercover completely rely on the instructions of his leader to work, the leadership said a few actions, he must follow the time to carry out, if the action time change, he will immediately change his time to cooperate with the action. The leader sent two undercover men to infiltrate the enemy's interior. Then the leader is equivalent to the abstract theme, and Inspector Officer John this person sent two undercover dick and Wan Wang, John is equivalent to a specific theme, undercover equivalent to the abstract observer, the two undercover is Dick and Harry is a specific observer, sent this action is equivalent to the observer in the subject of registration. So the class diagram is as follows:
Implemented using JAVAAPI, the code is described as follows:
Package observer;
Import java.util.List;
Import java.util.Observable;
Import Java.util.Observer;
/**
* Description: Police John * * * Public
class Police extends observable {
private String time;
Public Police (list<observer> List) {
super ();
for (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 implements Observer {
private String time;
@Override public
void update (Observable o, Object Arg) {Time
= (String) arg;
System.out.println ("Undercover a received message, Action time:" +time);
}
Package observer;
Import java.util.Observable;
Import Java.util.Observer;
/**
* Description: Undercover b */public
class Undercoverb implements Observer {
private String time;
@Override public
void update (Observable o, Object Arg) {Time
= (String) arg;
System.out.println ("Undercover B received message, Action time:" +time);
}
Package observer;
Import java.util.ArrayList;
Import java.util.List;
Import Java.util.Observer;
/**
* Description: Test
/public class Client {
/**
* @param args
/public
static void main (string[ ] {
Undercovera O1 = new Undercovera () args);
Undercoverb O2 = new Undercoverb ();
list<observer> list = new arraylist<> ();
List.add (O1);
List.add (O2);
Police subject = new Police (list);
Subject.change ("02:25");
System.out.println ("=========== due to news, action time Advance =========");
Subject.change ("01:05");
}
Test Run Results:
Undercover B received news, action time: 02:25
undercover A received news, action time: 02:25
=========== due to news, action time in advance =========
Undercover B received message, Action time: 01:05
undercover a received the message, the action time is: 01:05
Iv. Summary
The Observer pattern defines a one-to-many relationship between objects, and objects that depend on it are notified when the state of an object (observed) changes. Can be applied to publishing--subscriptions, changes--to update this business scenario.
In a loosely coupled way between the observer and the observed, the observer does not know the details of the observer and only knows that the observer implements the interface.
The event-driven model is more flexible, but it pays for the complexity of the system as we tailor a listener and event to each event source, which increases the burden on the system.
The core of the observer pattern is to distinguish roles, locate good observers and the observed, and they are many-to-many relationships. The key to achieving this is to establish a link between the observer and the observed, such as having a set in the Observer class that is used to store the observer and notify all observers when the detected changes. In the observer's method of construction, the observer is passed in and registers itself in the list of observers owned by the Observer, that is, the observers list.
1. Advantages of the Observer model:
(1) Abstract subjects depend only on the abstract observer
(2) Observer mode supports broadcast communication
(3) The Observer pattern separates the information generation layer from the response layer
2. Shortcomings of the Observer model:
(1) If a subject is registered by a large number of observers, it will cost a high price to notify all observers
(2) If the response of some observers is blocked, the entire notification process is blocked and other observers are not notified in time