The observer pattern of Java and patterns
In the book "Java and Patterns" of Dr. Shanhong, this describes the Observer (Observer) pattern:
The Observer pattern is the behavior pattern of the object, also called the Publish-subscribe (publish/subscribe) mode, the Model-view (Model/view) mode, the source-listener (Source/listener) mode, or the slave (dependents) mode.
The Observer pattern defines a one-to-many dependency that allows multiple observer objects to listen to a Subject object at the same time. When the subject object changes in state, all observer objects are notified so that they can automatically update themselves.
structure of the Observer pattern
A software system contains a variety of objects, like a thriving forest full of creatures. In a forest, all kinds of organisms depend on each other and bind to form a chain of life. The state change of one organism causes the corresponding action of other organisms, each of which is in the interaction of other organisms.
Similarly, a software system often requires changes in the state of an object, and some other objects make corresponding changes. There are many design options to do this, but in order to make the system easy to reuse, a low-coupling design should be chosen. Reducing the coupling between objects facilitates the reuse of the system, but designers need to enable these low-coupling objects to maintain coordination of actions and ensure a high degree of collaboration. The Observer pattern is the most important of the various design scenarios that satisfy this requirement.
The following is an example of a simple schematic implementation that discusses the structure of the observer pattern.
The actors involved in the Observer pattern are:
Abstract Theme (Subject) role: Abstract Theme The role holds all references to observer objects in a single aggregation (such as a ArrayList object), each subject can have any number of observers. Abstract topics provide an interface that can add and remove observer objects, and abstract subject roles are also known as abstract Observer (Observable) roles.
specific subject (ConcreteSubject) role: The status of the State is deposited into the specific observer object, and all registered observers are notified when the internal state of the specific subject changes. The specific subject role is also called the specific Observer (concrete Observable) role.
abstract Observer (Observer) Role: defines an interface for all specific observers, updating themselves when the topic is notified, an interface called the update interface.
specific observer (concreteobserver) role: stores the state of the subject with the status itself. The specific observer role implements the update interface required by the abstract observer role in order to reconcile the state of itself with the state of the subject. If desired, the specific observer role can maintain a reference to a specific subject object.
Source
Abstract Theme Role Classes
Public abstract class Subject { /** * is used to save the registered Observer Object */ private list<observer> List = new Arraylist<observer> (); /** * Register Observer Object @param observer Observer Object */public VOID attach (Observer observer) { LIST.ADD (Observer); System.out.println ("attached an observer"); /** * Delete Observer object @param observer Observer Object */public VOID Detach (Observer observer) { LIST.REMOVE (Observer); } /** * Notifies all registered Observer objects */ public void Nodifyobservers (String newstate) {for (Observer observer:list) { observer.update (newstate); }}}
Specific Theme Role Classes
public class ConcreteSubject extends subject{ private String state; Public String getState () { return state; } public void Change (String newstate) {state = newstate; System.out.println ("Subject Status:" + state); The status changes, notifying the individual observers this.nodifyobservers (state);} }
Abstract Observer Role Class
Public interface Observer { /** * Update interface @param State Update Status */public void Update ( String state);
Specific Observer Role classes
public class Concreteobserver implements Observer { //Observer's state private String observerstate; @Override public void Update (String state) { /** * Updates the status of the observer so that it is consistent with the status of the target */ observerstate = State ; System.out.println ("Status:" +observerstate);} }
Client class
public class Client {public static void Main (string[] args) { //Create Subject Object ConcreteSubject subject = new CONCR Etesubject (); Create observer object Observer Observer = new Concreteobserver (); Register the Observer object on the Subject Object Subject.attach (Observer); Change the status of the Subject Object subject.change ("New State");} }
The operation results are as follows
At run time, the client first creates an instance of a specific topic class, and an Observer object. It then invokes the attach () method of the Subject object, registering the Observer object with the subject object, that is, adding it to the aggregation of the subject object.
At this point, the client invokes the topic's change () method, changing the internal state of the subject object. When a Subject object changes state, the Notifyobservers () method of the superclass is called to notify all registered observer objects.
Push models and pull models
In the observer mode, it is divided into two ways: push model and pull model.
Push Model
The subject object pushes the details of the topic to the observer, and the information that is pushed is usually all or part of the data of the subject object, regardless of whether or not the observer needs them.
Pull Model
The Subject object transmits only a small amount of information when it notifies the observer. If the observer needs more specific information, the Observer takes the initiative to get to the subject object, which is equivalent to the observer pulling data from the subject object. In the general implementation of this model, the subject object itself is passed to the observer through the update () method, which can be obtained by this reference when the observer needs to obtain the data.
According to the above description, it is found that the previous example is a typical push model, the following gives an example of a pull model.
Abstract Observer class for pull models
Pull models usually pass the subject object as a parameter.
Public interface Observer { /** * Update interface @param subject incoming Subject object, aspect gets the status of the corresponding Subject Object * /public void Update (Subject Subject);}
Specific observer classes for pull models
public class Concreteobserver implements Observer { //Observer's state private String observerstate; @Override public void Update (Subject Subject) { /** * Updates the state of the observer so that it is consistent with the state of the target */ observerstate = ( ConcreteSubject) subject). GetState (); SYSTEM.OUT.PRINTLN ("Observer status:" +observerstate);} }
Abstract topic classes for pull models
The main change in the abstract theme class of Pull models is the Nodifyobservers () method. The parameters passed in are different when the observer is looped, that is, when the Observer's update () method is called.
Public abstract class Subject { /** * is used to save the registered Observer Object */ private list<observer> List = new Arraylist<observer> (); /** * Register Observer Object @param observer Observer Object */public VOID attach (Observer observer) { LIST.ADD (Observer); System.out.println ("attached an observer"); /** * Delete Observer object @param observer Observer Object */public VOID Detach (Observer observer) { LIST.REMOVE (Observer); } /** * Notifies all registered Observer objects * /public void Nodifyobservers () {for (Observer observer:list) { Observer.update (this); }}}
Specific theme classes for pull models
Compared with the push model, there is a little change, that is, when invoking the method of notifying the observer, it is not necessary to pass in the parameters.
public class ConcreteSubject extends subject{ private String state; Public String getState () { return state; } public void Change (String newstate) {state = newstate; System.out.println ("Subject Status:" + state); The state changes, notifying each observer this.nodifyobservers ();} }
Comparison of the two modes
The push model is the assumption that the subject object knows the data that the observer needs, whereas the pull model is a subject object that does not know what data the observer specifically needs, and if there is no way, simply pass it on to the observer, allowing the observer to take the value on its own.
Pushing a model may make it difficult to reuse the observer object because the Observer's update () method is a parameter that is defined as needed, and may not be able to take into account unused usage. This means that a new update () method may be available when a new situation arises, or simply a re-implementation of the observer, whereas the pull model does not cause this, since the parameters of the update () method under the pull model are the subject object itself, which is basically the largest collection of data that the subject object can deliver. Can basically adapt to the needs of various situations.
Java-provided support for observer patterns
In the Java language Java.util Library, a observable class and a observer interface are provided, which form the Java language support for the Observer pattern.
Observer interface
This interface defines only one method, the update () method, which is called by the Notifyobservers () method of the Observer object when the state of the object being observed changes.
Public interface Observer { void update (Observable o, Object arg);}
Observable class
The Observer class is a subclass of the Java.util.Observable class. Java.util.Observable provides a public way to support the Observer object, where two of these methods are important for observable subclasses: one is setchanged () and the other is Notifyobservers (). The first method setchanged () is called and an internal tag variable is set, representing the state of the object being observed to change. The second is notifyobservers (), which, when called, invokes the update () method of all registered observer objects so that the observer objects can update themselves.
public class Observable {Private Boolean changed = FALSE; Private Vector Obs; /** Construct an Observable with zero observers. */Public Observable () {obs = new Vector (); /** * Add an observer to the Observer aggregation */public synchronized void Addobserver (Observer o) {if (o = = null) throw new NullPointerException (); if (!obs.contains (o)) {obs.addelement (o); }}/** * Remove an observer from the Observer aggregation */public synchronized void Deleteobserver (Observer o) {obs.removeeleme NT (o); } public void Notifyobservers () {notifyobservers (null); }/** * If this object changes (at that time the Haschanged method returns True) * Call this method to notify all registered observers that the update () method that called them is passed in this and arg as parameters */Publ IC void Notifyobservers (Object arg) {object[] arrlocal; Synchronized (this) {if (!changed) return; arrlocal = Obs.toarray (); Clearchanged (); } for (int i = arrlocal.length-1; i>=0; i--)((Observer) arrlocal[i]). Update (this, ARG); }/** * Will gather the observers to empty */public synchronized void Deleteobservers () {obs.removeallelements (); }/** * Set "changed" to True */protected synchronized void setchanged () {changed = TRUE; }/** * Resets "changed" to False */protected synchronized void clearchanged () {changed = FALSE; }/** * Detects if this object has changed */public synchronized Boolean hasChanged () {return changed; }/** * Returns the number of observers of this <tt>Observable</tt> object. * *@return The number of observers of this object. */Public synchronized int countobservers () {return obs.size (); }}
This class represents an observer object, sometimes called a subject object. An observer object can have several observer objects, and each observer object is an object that implements the Observer interface. When the observer changes, the observable's Notifyobservers () method is called, which invokes the update () method of all the specific observers, so that all observers are notified to update themselves.
How to use Java to support observer patterns
Here is a very simple example of how to use Java to provide support for the observer pattern. In this case, the observed object is called watched, and the Observer object is called Watcher. The watched object inherits from the Java.util.Observable class, while the Watcher object implements the Java.util.Observer interface. There is also a test class that acts as a client role.
Source
Observer watched class source code
Public class watched extends observable{ private String data = ""; Public String GetData () { return data; } public void SetData (String data) { if (!this.data.equals (data)) { this.data = data; Setchanged (); } Notifyobservers (); } }
Observer class source code
public class Watcher implements observer{public watcher (Observable o) { o.addobserver (this); } @Override public void update (Observable o, Object Arg) { System.out.println ("status changed:" + ((watched) O). GetData ()); }}
Test class source Code
public class Test {public static void Main (string[] args) { //Create observer object watched watched = new watched (); Create the Observer object and register the Observer object Observer Watcher = new Watcher (watched); Assigning a Watched.setdata ("Start") to the observed state; Watched.setdata ("Run"); Watched.setdata ("Stop");} }
The test object first creates the watched and Watcher objects. When the Watcher object is created, the watched object is passed in as a parameter, and then the test object invokes the SetData () method of the watched object, triggering the internal state change of the watched object, and the watched object informs the implementation of the registered watcher object , which is the update () method that calls it.
Java Watcher pattern