Java Observer design patterns (Observable and Observer)

  • 2020-04-01 04:28:28
  • OfStack

The observer pattern defines a one-to-many dependency in which multiple observer objects listen to a topic object simultaneously.

When the subject object changes state, all observer objects are notified so that they can update themselves automatically.

I. introduction of observer mode

The Observer pattern is implemented in Java by Observable and Observer interface. An Observer monitors an Observable for changes, and when the Observable changes, the Observer is notified and can work accordingly.

If screen A shows the data in the database, and screen B modifies the data in the database, then screen A will Load again. This is where the observer mode comes in

Two, the observer mode implementation method

There are two methods in java.util.Observable that are particularly important to the Observer

1) setChanged () method


 
protected void setChanged() { 
changed = true; 
} 
 2. notifyObservers() methods  / notifyObservers(Object data) methods 
[java] view plaincopy
 
public void notifyObservers() { 
notifyObservers(null); 
} 
 
@SuppressWarnings("unchecked") 
public void notifyObservers(Object data) { 
int size = 0; 
Observer[] arrays = null; 
synchronized (this) { 
if (hasChanged()) { 
clearChanged(); 
size = observers.size(); 
arrays = new Observer[size]; 
observers.toArray(arrays); 
} 
} 
if (arrays != null) { 
for (Observer observer : arrays) { 
observer.update(this, data); 
} 
} 
} 

These two approaches are important

- setChanged () method

Used to set an internal flag to indicate that the data has changed
NotifyObservers () method/notifyObservers(Object data) method --
Notifying all observers that the data has changed, all observers will automatically call the replicated update(Observable, Object data) method to do some processing (such as updating the screen data).
We can see that there are two ways to notify the Observer, one with no arguments and one with arguments. So what does this parameter do?
For one thing: now that I don't want to notify all the observers, but just want one of them to do something, I can pass a parameter as an ID, and then judge it in all the observers, and each Observer will only do something if it receives the parameter ID as its own.

Of course there are other things that parameters can do, and I'm just giving you an example.

Here is an example to illustrate:


import java.util.Observable; 
 
public class SimpleObservable extends Observable 
{ 
private int data = 0; 
public int getData(){ 
return data; 
} 
public void setData(int i){ 
if(this.data != i) { 
this.data = i; 
setChanged(); 
//NotifyObservers () calls update() only after setChange() is called, otherwise nothing happens.
notifyObservers(); 
} 
} 
} 

The above class is an observed class that inherits from the Observable class to indicate that the class can be observed.
From within the setData() method, where the data changes, the Observable setChanged() method and notifyObservers() method are called to indicate that the data has changed and to notify all observers to call their update() method for some processing.

Note: notifyObservers() calls update() only after setChange() is called, otherwise nothing happens.


 
public class SimpleObserver implements Observer 
{ 
public SimpleObserver(SimpleObservable simpleObservable){ 
simpleObservable.addObserver(this ); 
} 

public void update(Observable observable ,Object data){ //Data is an arbitrary object that is used to pass parameters
System.out.println( " Data has changed to "  + (SimpleObservable)observable.getData()); 
} 
} 

The addObserver(this) method is called to make the observer (SimpleObservable) observe by generating an instance of the observed (SimpleObservable).
Then I have to copy the update() method to do some processing after the data changes.

Now you can write a simple test class to test it


public class SimpleTest 
{ 
public static void main(String[] args){ 
SimpleObservable doc = new SimpleObservable (); 
SimpleObserver view = new SimpleObserver (doc); 
doc.setData(1); 
doc.setData(2); 
doc.setData(2); 
doc.setData(3); 
} 
} 

The results are as follows

Data has changed to 1
Data has changed to 2 // the second time setData(2), the update is not called because there is no setChange
Data has changed to 3

Here are some other attributes and methods of an Observable

Attributes -

// observers is a List that holds all observers to be notified.
List< Observer> Observers = new ArrayList< Observer> (a);
// changed is a Boolean flag bit that indicates whether the data has changed.
Boolean changed = false;

Methods -


//Add an Observer to list observers
public void addObserver(Observer observer) { 
if (observer == null) { 
throw new NullPointerException(); 
} 
synchronized (this) { 
if (!observers.contains(observer)) 
observers.add(observer); 
} 
} 
//Remove an observer from list observers
public synchronized void deleteObserver(Observer observer) { 
observers.remove(observer); 
} 
//Clear list faces
public synchronized void deleteObservers() { 
observers.clear(); 
} 
//Returns the number of observers in list observers
public int countObservers() { 
return observers.size(); 
} 
//Reset the data change flag bit to unchanged
protected void clearChanged() { 
changed = false; 
} 
//Sets the data change flag bit to change
protected void setChanged() { 
changed = true; 
} 
//Determines the value of the flag bit
public boolean hasChanged() { 
return changed; 
} 
//Notify all observers (no participation)
public void notifyObservers() { 
notifyObservers(null); 
} 
//Notify all observers (with participation)
@SuppressWarnings("unchecked") 
public void notifyObservers(Object data) { 
int size = 0; 
Observer[] arrays = null; 
synchronized (this) { 
if (hasChanged()) { 
clearChanged(); 
size = observers.size(); 
arrays = new Observer[size]; 
observers.toArray(arrays); 
} 
} 
if (arrays != null) { 
for (Observer observer : arrays) { 
observer.update(this, data); 
} 
} 
} 

Note: make sure that the Observer object is deleted from the list with deleteObserver before it is destroyed, i.e. the deleteObserver() method is called in the onDestroy() method.

Otherwise, because there is still an object reference, the Observer object will not be garbage collected, causing a memory leak, and the dead Observer will still be notified, potentially causing unexpected errors, and notifyObservers will slow down as the list grows.

The roles involved in the observer model are:

low Subject role: the abstract topic role stores all references to observer objects in an aggregate (such as an ArrayList object), and each topic can have any number of observers. Abstract topics provide an interface to add and remove observer objects. The abstract topic role is also called the Observable role.

low ConcreteSubject role: storing the relevant state in a specific observer object; Notification is given to all registered observers when the internal status of a particular subject changes. Specific thematic roles are also called Concrete Observable roles.

low the abstract Observer role: define an interface for all concrete observers to update themselves when notified of the topic. This interface is called the update interface.

low the ConcreteObserver role: a state that stores the state of the topic in its own right. The concrete observer role implements the updated interface required by the abstract observer role to coordinate its own state with that of the subject. The specific observer role can hold a reference to a specific topic object if needed.


Related articles: