Observer pattern is a behavioral design pattern. The use of the Observer pattern is when you are interested in the state of an object and want to be notified every time it changes. In the observer pattern, the object that observes the state of another object is called the Observer, and the observed object is called the Subject. According to GoF rules, the intent of the Observer pattern is:
Copy the code code as follows:
Define a one-to-many dependency relationship between objects. If the state of an object changes, other related objects will be notified and automatically updated.
Subjects contain observers that need to be notified when their state changes. Therefore, it should provide observers with methods to register themselves and unregister themselves. When the Subject (observed) changes, it also needs to include a method to notify all observers. When notifying observers, you can push updates or provide another method to obtain updates.
Observers should have a method that sets the observer object and can be used by the observed to notify it of updates.
JAVA provides built-in ways to implement the observer pattern, the java.util.Observable and java.util.Observer interfaces. However, they are not very widely used. Because this implementation is too simple, most of the time we don't want the last extended class to just implement the observer pattern, because JAVA classes cannot inherit multiple times.
Java Messages Service (JMS) message service uses the observer mode and command mode to realize the publication and subscription of data between different programs.
The MVC model-view-control framework also uses the observer pattern, treating the model as the observed and the view as the observer. Views can register themselves to the model to receive changes to the model.
Observer pattern example
In this example, we will complete a simple topic discussion, and observers can register for this topic. Any changes resulting from content submissions on this topic will be notified to all registered observers.
Based on the needs of the Subject's observers, this is to implement a basic Subject interface. This interface specifies a series of specific methods that need to be implemented in the specific class that subsequently implements the interface.
Copy the code code as follows:
package com.journaldev.design.observer;
public interface Subject {
//methods to register and unregister observers
public void register(Observer obj);
public void unregister(Observer obj);
//method to notify observers of change
public void notifyObservers();
//method to get updates from subject
public Object getUpdate(Observer obj);
}
Now create an associated observer. It needs a method to attach the Subject to an observer. Additional methods can accept Subject change notifications.
Copy the code code as follows:
package com.journaldev.design.observer;
public interface Observer {
//method to update the observer, used by subject
public void update();
//attach with subject to observe
public void setSubject(Subject sub);
}
This connection has been established. Now implement the concrete theme.
Copy the code code as follows:
package com.journaldev.design.observer;
import java.util.ArrayList;
import java.util.List;
public class MyTopic implements Subject {
private List<Observer> observers;
private String message;
private boolean changed;
private final Object MUTEX= new Object();
public MyTopic(){
this.observers=new ArrayList<>();
}
@Override
public void register(Observer obj) {
if(obj == null) throw new NullPointerException("Null Observer");
if(!observers.contains(obj)) observers.add(obj);
}
@Override
public void unregister(Observer obj) {
observers.remove(obj);
}
@Override
public void notifyObservers() {
List<Observer> observersLocal = null;
//synchronization is used to make sure any observer registered after message is received is not notified
synchronized (MUTEX) {
if (!changed)
return;
observersLocal = new ArrayList<>(this.observers);
this.changed=false;
}
for (Observer obj : observersLocal) {
obj.update();
}
}
@Override
public Object getUpdate(Observer obj) {
return this.message;
}
//method to post message to the topic
public void postMessage(String msg){
System.out.println("Message Posted to Topic:"+msg);
this.message=msg;
this.changed=true;
notifyObservers();
}
}
The implementation of registering and unregistering observer methods is very simple. The additional method postMessage() will be used by the client to submit a string message to this topic. Note that Boolean variables are used to track changes in the topic state and notify observers of such changes. This variable is necessary because if there is no update, but someone calls the notifyObservers() method, he cannot send error notification information to the observers.
In addition, it should be noted that synchronization is used in notifyObservers() to ensure that notifications can only be sent to registered observers before the message is published to the topic.
Here is the implementation of the observer. They will always focus on the subject object.
Copy the code code as follows:
package com.journaldev.design.observer;
public class MyTopicSubscriber implements Observer {
private String name;
private Subject topic;
public MyTopicSubscriber(String nm){
this.name=nm;
}
@Override
public void update() {
String msg = (String) topic.getUpdate(this);
if(msg==null){
System.out.println(name+":: No new message");
}else
System.out.println(name+":: Consuming message::"+msg);
}
@Override
public void setSubject(Subject sub) {
this.topic=sub;
}
}
Note that the implementation of the update() method uses the observer's getUpdate() to handle updated messages. Passing the message as a parameter to the update() method should be avoided here.
Here is a simple test program to verify the implementation of the topic class.
Copy the code code as follows:
package com.journaldev.design.observer;
public class ObserverPatternTest {
public static void main(String[] args) {
//create subject
MyTopic topic = new MyTopic();
//create observers
Observer obj1 = new MyTopicSubscriber("Obj1");
Observer obj2 = new MyTopicSubscriber("Obj2");
Observer obj3 = new MyTopicSubscriber("Obj3");
//register observers to the subject
topic.register(obj1);
topic.register(obj2);
topic.register(obj3);
//attach observer to subject
obj1.setSubject(topic);
obj2.setSubject(topic);
obj3.setSubject(topic);
//check if any update is available
obj1.update();
//now send message to subject
topic.postMessage("New Message");
}
}
Here is the above output:
Copy the code code as follows:
Obj1:: No new message
Message Posted to Topic:New Message
Obj1::Consuming message::New Message
Obj2::Consuming message::New Message
Obj3::Consuming message::New Message</pre>
UML diagram of Observer pattern
The observer pattern is also called the publish-subscribe pattern. Some specific applications in JAVA are as follows:
1.java.util.EventListener in Swing
2.javax.servlet.http.HttpSessionBindingListener
3.javax.servlet.http.HttpSessionAttributeListener
The above are all observer modes. Hope you like it already. Share your feelings in the comments or please share with others.