I'm trying to understand the observer pattern , this is a simple code that I picked online :
import java.util.ArrayList;
import java.util.List;
/**
* The observer pattern is a software design pattern in which an object,
* called the subject, maintains a list of its dependents, called observers, and
* notifies them automatically of any state changes, usually by calling one of their methods
* @author X220
*
*/
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);
}
interface Observer
{
// method to update the observer, used by subject
public void update();
// attach with subject to observe
public void setSubject(Subject sub);
}
/**
* Holds a list of the observers
* @author X220
*
*/
class MySubject implements Subject
{
private List<Observer> observers;
private String message;
private boolean changed;
private final Object MUTEX = new Object();
public MySubject()
{
this.observers = new ArrayList<>();
}
@Override
public void register(Observer obj)
{
if (obj == null)
throw new NullPointerException("Null Observer");
synchronized (MUTEX) {
if (!observers.contains(obj))
observers.add(obj);
}
}
@Override
public void unregister(Observer obj)
{
synchronized (MUTEX)
{
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();
}
}
class MyObserver implements Observer
{
private String name;
private Subject topic;
public MyObserver(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;
}
}
public class RunCode1
{
public static void main1(String[] args) {
// create subject
MySubject topic = new MySubject();
// create observers
Observer obj1 = new MyObserver("Obj1");
Observer obj2 = new MyObserver("Obj2");
Observer obj3 = new MyObserver("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");
}
}
Pretty much I got the idea , but one thing bothers me : the Observer has a setSubject()
method , and he himself( the observer) also registers to subject and also sets the Subject , which seems to me a little bit wrong .
I can change the interface and remove the setSubject()
method , however my question is do I really need also to set a subject after registering , from the Observer pattern point of view ?
You are right, this method adds an unnecessary dependancy, because of this line:
String msg = (String) topic.getUpdate(this);
These two methods ( setSubject
and getUpdate
) can be removed and msg
can be retrieved direcly from update()
, like this:
@Override
public void update(String msg) {
if (msg == null) {
System.out.println(name + ":: No new message");
} else
System.out.println(name + ":: Consuming message::" + msg);
}
With the update in notifyObservers
:
for (Observer obj : observersLocal)
{
obj.update(this.message);
}
Well, the observer has to know specifics about his subject, otherwise he wouldn't be able to observe it, right? Matched to real life: you also have to know those specifics about an object you are observing to know when you need to take specific actions, right?
The thing is, you can decouple it with interfaces , so you're able to build a much more generalised observer... Then your observed objects just need to implement that observing-interface and your observer is ready to go.
Let's look at the Observer pattern as defined by the GoF in UML from 1995:
ConcreteObserver
has a link subject
to a ConcreteSubject
-- the pattern doesn't specify how you set it up; it could be injected in a constructor or with a setSubject()
method as you've done.
On the Subject
side, your code has register
and unregister
, which are analogous to Attach
and Detach
, and your notifyObservers
fits the pattern, too.
do I really need also to set a subject after registering , from the Observer pattern point of view?
According to this GoF version of the pattern, somehow the ConcreteObserver
has to know the subject in order to update itself. So, you need to set a subject.
There is a variant of the pattern (Java's Observer
/ Observable
) where the Update()
method passes an object that contains the state-relevant information such that the ConcreteObserver
can update its state without having to communicate with the ConcreteSubject
. Theoretically you wouldn't need to store a link to the subject then.
The goal of the pattern is not to eliminate all dependencies. In software development, there is a tendency to want to add new observers (think of how many versions of the GUI there have been for Microsoft Word). The subjects are classes that tend not to have code changes. A rule in software design is to create dependencies on classes that are not likely to have changes in their code . The Observer pattern is saying that ConcreteObservers
tend to change (there are new versions over time), and so we don't want to have to also change the ConcreteSubjects
.
The pattern doesn't help if you change a subject's code. For example, let's take a subject that represents the remaining charge of the battery of a mobile phone, and its value is ranging from 0 to 10. Several observers display that information using graphics or colors; perhaps when the value is below 2, the observer displays a red image. Now, if a developer decides that it's better to show values from 0 to 100, since it has more resolution for knowing how long the battery lasts, you would have to change the code of all the observers (they depend on the subjects).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.