Simple Observer Pattern implementation
Copy Code code as follows:
Import java.util.ArrayList;
Import java.util.Collections;
Import Java.util.Iterator;
Import java.util.List;
/**
* The callback is used in the Observer mode:
* A. The observer registers itself with the listener list of the observer, and the Observer class itself provides a callback function
* B. The Observer (observable or subject) maintains a list of observers and can register and reconcile the Observer
* C. Once the observer State has changed, it can invoke Notifyobservers (), which traverses the list of observers and calls each
The callback function provided by the Observer
* @author would
*
*/
public class Simpleobserverpattern {
public static void Main (string[] args) {
Simpleobserverpattern sop = new Simpleobserverpattern ();
List<iobserver> observers = new arraylist<iobserver> ();
IObserver Observera = sop.new Observer ("Observera");
IObserver Observerb = sop.new Observer ("Observerb");
Observers.add (Observera);
Observers.add (Observerb);
IObservable observable = Sop.new observable (observers);
Observable.registerobserver (sop.new Observer ("Observerc"));
Observable.changestate ();
Observable.close ();
}
Being observed, some place called subject
Interface IObservable {
VOID Registerobserver (IObserver observer);
VOID Unregisterobserver (IObserver observer);
void Notifyobservers ();
String getState ();
void Changestate ();
void Close ();
}
Class Observable implements IObservable {
Private static final String new = "new";
private static final String CHANGED = "CHANGED";
private static final String CLOSED = "CLOSED";
Private String State;
Private list<iobserver> observers;
Public observable () {
this (null);
}
Public observable (list<iobserver> observers) {
if (observers = = NULL) {
Observers = new arraylist<iobserver> ();
}
This.observers = Collections.synchronizedlist (observers);
This.state = NEW;
}
@Override
public void Registerobserver (IObserver observer) {
OBSERVERS.ADD (Observer);
}
@Override
public void Unregisterobserver (IObserver observer) {
OBSERVERS.REMOVE (Observer);
}
@Override
public void Notifyobservers () {
Iterator<iobserver> iter = Observers.iterator ();
while (Iter.hasnext ()) {
Iter.next (). Update (this);
}
}
@Override
Public String getState () {
return state;
}
@Override
public void Changestate () {
This.state = CHANGED;
Notifyobservers ();
}
@Override
public void Close () {
This.state = CLOSED;
Notifyobservers ();
}
}
Interface IObserver {
void Update (iobservable observalbe);
}
Class Observer implements IObserver {
private String name;
Public Observer (String name) {
THIS.name = name;
}
@Override
public void Update (IObservable observalbe) {
System.out.println (
String.Format ("%s receive Observalbe ' s change, current Observalbe ' s state is%s",
Name, Observalbe.getstate ()));
}
}
}
The above implementation directly takes the object of the Observer as a callback function parameter, which is not elegant and may work in a simple scenario.
But in fact more often than not, an observer has many kinds of events or States, and each observer may be interested in a different event or state, or, for the purpose of information hiding, does not want each observer to have access to all states within the observable.
So I went on to evolve the code for the following version, noting that I did not consider concurrency issues very carefully here.
Copy Code code as follows:
Import java.util.Collections;
Import Java.util.HashSet;
Import java.util.Hashtable;
Import Java.util.Iterator;
Import Java.util.Set;
public class Multieventobserverpattern {
public static void Main (string[] args) {
Multieventobserverpattern Meop = new Multieventobserverpattern ();
IObservable observable = Meop.new observable ();
IObserver Observera = meop.new Observer ("Observera");
IObserver Observerb = meop.new Observer ("Observerb");
Registering events of Interest
Observable.registerobserver (Observable.geteventa (), Observera);
Observable.registerobserver (OBSERVABLE.GETEVENTB (), observerb);
Change the state of being observed
Observable.changestatea ();
Observable.changestateb ();
}
Interface IEvent {
void Eventchange ();
String getState ();
}
Class Eventa implements IEvent {
Private static final String initialized = "initialized";
private static final String PENDING = "PENDING";
Private String State;
Public Eventa () {
This.state = initialized;
}
@Override
public void Eventchange () {
System.out.println ("Eventa change");
This.state = PENDING;
}
@Override
Public String toString () {
return "Eventa";
}
@Override
Public String getState () {
return state;
}
}
Class Eventb implements IEvent {
Private static final String new = "new";
private static final String IDLE = "IDLE";
Private String State;
Public Eventb () {
This.state = NEW;
}
@Override
public void Eventchange () {
System.out.println ("Eventb change");
This.state = IDLE;
}
@Override
Public String toString () {
return "EVENTB";
}
@Override
Public String getState () {
return state;
}
}
The observed (observable), some places are called subject
Interface IObservable {
void Registerobserver (IEvent event, iobserver observer);
void Unregisterobserver (IEvent event, iobserver observer);
Inform the Observer that an event has occurred
void Notifyobservers (IEvent event);
void Changestatea ();
void Changestateb ();
IEvent Geteventa ();
IEvent Geteventb ();
}
Class Observable implements IObservable {
Private IEvent Eventa;
Private IEvent EVENTB;
Private hashtable<ievent, set<iobserver>> eventobservermapping;
Public observable () {
this (null);
}
Here if some of the set<iobserver> passed in by Evenobservermapping are not synchronized, then there is no way
Public observable (hashtable<ievent, set<iobserver>> eventobservermapping) {
if (eventobservermapping = = null) {
eventobservermapping = new hashtable<ievent, set<iobserver>> ();
}
this.eventobservermapping = new hashtable<ievent, set<iobserver>> ();
This.eventa = new Eventa ();
THIS.EVENTB = new Eventb ();
}
@Override
public void Registerobserver (IEvent event, IObserver observer) {
Set<iobserver> observers = Eventobservermapping.get (event);
if (observers = = NULL) {
Observers = Collections.synchronizedset (New hashset<iobserver> ());
OBSERVERS.ADD (Observer);
Eventobservermapping.put (event, observers);
}
else {
OBSERVERS.ADD (Observer);
}
}
@Override
public void Unregisterobserver (IEvent event, IObserver observer) {
Set<iobserver> observers = Eventobservermapping.get (event);
if (observers!= null) {
OBSERVERS.REMOVE (Observer);
}
}
@Override
public void Notifyobservers (IEvent event) {
Set<iobserver> observers = Eventobservermapping.get (event);
if (observers!= null && observers.size () > 0) {
Iterator<iobserver> iter = Observers.iterator ();
while (Iter.hasnext ()) {
Iter.next (). Update (event);
}
}
}
@Override
public void Changestatea () {
Changing state A will trigger event a
Eventa.eventchange ();
Notifyobservers (Eventa);
}
@Override
public void Changestateb () {
Changing State B will trigger event B
Eventb.eventchange ();
Notifyobservers (EVENTB);
}
@Override
Public IEvent Geteventa () {
return Eventa;
}
@Override
Public IEvent Geteventb () {
return EVENTB;
}
}
Interface IObserver {
void Update (IEvent event);
}
Class Observer implements IObserver {
private String name;
Public Observer (String name) {
THIS.name = name;
}
@Override
public void Update (IEvent event) {
System.out.println (
String.Format ('%s receive%s ' Change, current Observalbe ' s '%s ',
Name, event, Event.getstate ());
}
}
}
It seems perfect, but it's not perfect. Because the event is hard-coded into the properties of the observed class. Such event types are fixed at compile time, and if you want to add new event types you have to modify the IObservable interface and the observable class, this greatly reduces the flexibility.
As the observer is coupled with these specific events, how can we break the limit?
The answer is to introduce a new component that allows the component to manage the relationship between the event, observer, and observer, and the component to invoke the Observer's callback function when the event occurs. This is also a decoupling bar, something similar to spring's IOC container.
As for the specific implementation, I think guava Eventbus has done a good job, you can refer to the link I mentioned earlier.
PS: This post is not for guava Eventbus advertising, but their own thinking step by step, gradually and guava eventbus design ideas coincide.
Let's continue with the example of the JDK standard class implementing the Observer pattern, then analyze its source code implementation to see only one observable class and one observer interface.
JDK Standard class implements observer mode
Copy Code code as follows:
Import java.util.Observable;
Import Java.util.Observer;
/**
* Using the standard classes in the Java.util package to implement the Observer pattern
* @author would
*
*/
public class Jdkobserverdemo {
public static void Main (string[] args) {
Jdkobserverdemo jod = new Jdkobserverdemo ();
The person being observed
Myobservable myobservable = jod.new myobservable ("Hello");
Observer
Observer myobserver = Jod.new myobserver ();
Registered
Myobservable.addobserver (Myobserver);
Change the observer State, triggering the observer callback function
Myobservable.setvalue ("would");
}
Class Myobservable extends Observable {
Private String Watchedvalue; The observed value
Public myobservable (String watchedvalue) {
This.watchedvalue = Watchedvalue;
}
public void SetValue (String newvalue) {
if (!watchedvalue.equals (NewValue)) {
Watchedvalue = newvalue;
Setchanged ();
Notifyobservers (NewValue);
}
}
@Override
Public String toString () {
return "myobservable";
}
}
Class Myobserver implements Observer {
@Override
public void update (observable o, Object Arg) {
SYSTEM.OUT.PRINTLN (o + "' s state changed, argument is:" + arg);
}
}
}
See the JDK Standard library in the observer and observable implementation is very simple, do not want to say more.
The following is the listener implementation in quartz.
Quartzscheduler was supervised by the listener
Copy Code code as follows:
Import java.util.ArrayList;
Import Java.util.Date;
Import java.util.List;
/**
* Quartz core class, equivalent to observable (observed)
* @author would
*
*/
public class Quartzscheduler {
Private arraylist<schedulerlistener> internalschedulerlisteners = new arraylist<schedulerlistener> (10);
Private arraylist<joblistener> interanljoblisteners = new arraylist<joblistener> (); A observable can contain multiple sets of listeners
Public Date schedulejob (Trigger Trigger) {
if (trigger = = null) {
return null;
}
System.out.println ("Schedule job, Trigger:" + trigger);
Notifyschedulerlistenersscheduled (trigger);
return new Date ();
}
public void Unschedulejob (Trigger Trigger) {
if (trigger = = null) {
Return
}
System.out.println ("Unschedule job, Trigger:" + trigger);
Notifyshedulerlistenerunscheduled (trigger);
}
Register Schedulerlistener
public void Addinternalschedulerlistener (Schedulerlistener schedulerlistener) {
Synchronized (internalschedulerlisteners) {
Internalschedulerlisteners.add (Schedulerlistener);
}
}
Remove Schedulerlistener
public boolean Removeinternalschedulerlistener (Schedulerlistener schedulerlistener) {
Synchronized (internalschedulerlisteners) {
Return Internalschedulerlisteners.remove (Schedulerlistener);
}
}
Public list<schedulerlistener> getinternalschedulerlisteners () {
Synchronized (internalschedulerlisteners) {
Return Java.util.Collections.unmodifiableList (New arraylist<schedulerlistener> (internalschedulerlisteners) );
}
}
public void notifyschedulerlistenersscheduled (Trigger Trigger) {
For (Schedulerlistener listener:getinternalschedulerlisteners ()) {
Listener.jobscheduled (trigger);
}
}
public void notifyshedulerlistenerunscheduled (Trigger Trigger) {
For (Schedulerlistener listener:getinternalschedulerlisteners ()) {
Listener.jobunscheduled (trigger);
}
}
}
Schedulerlistener
Copy Code code as follows:
Listener interface, callback function, client registration listener need to provide callback function implementation
Public interface Schedulerlistener {
void jobscheduled (Trigger Trigger);
void jobunscheduled (Trigger Trigger);
}
Trigger
Copy code code as follows:
Trigger
public class Trigger {
Private String Triggerkey;
Private String triggername;
Public Trigger (String triggerkey, string triggername) {
This.triggerkey = Triggerkey;
This.triggername = triggername;
}
Public String Gettriggerkey () {
return triggerkey;
}
public void Settriggerkey (String triggerkey) {
This.triggerkey = Triggerkey;
}
Public String Gettriggername () {
return triggername;
}
public void Settriggername (String triggername) {
This.triggername = triggername;
}
Public String toString () {
Return String.Format ("{triggerkey:%s, Triggername:%s}", Triggerkey, Triggername);
}
}
Test
Copy Code code as follows:
public class Test {
public static void Main (string[] args) {
Quartzscheduler qs = new Quartzscheduler ();
Schedulerlistener Listenera = new Schedulerlistener () {
@Override
public void jobunscheduled (Trigger Trigger) {
System.out.println ("Listenera Job unscheduled:" + trigger.gettriggername ());
}
@Override
public void jobscheduled (Trigger Trigger) {
System.out.println ("Listenera Job scheduled:" + trigger.gettriggername ());
}
};
Schedulerlistener Listenerb = new Schedulerlistener () {
@Override
public void jobunscheduled (Trigger Trigger) {
System.out.println ("Listenerb Job unscheduled:" + trigger.gettriggername ());
}
@Override
public void jobscheduled (Trigger Trigger) {
System.out.println ("Listenerb Job scheduled:" + trigger.gettriggername ());
}
};
Register Scheduler Listener
Qs.addinternalschedulerlistener (Listenera);
Qs.addinternalschedulerlistener (Listenerb);
Trigger Triggera = new Trigger ("Key1", "Triggera");
Trigger Triggerb = new Trigger ("Key2", "Triggerb");
Qs.schedulejob (Triggera);
Qs.schedulejob (Triggerb);
Qs.unschedulejob (Triggera);
}
}