Design Patterns - Observer Pattern

The last article said the strategy pattern, this article, look at the observer pattern.

Let’s talk about the background of the code example in this article first. The requirement is a weather station that will observe atmospheric data in real time. Every time the data is updated, there will be multiple notice boards to display the updated data in time.

Just got it, the general idea may be like this

public class WeatherData{
//声明变量public void measurementsChanged(){float temp=getTemperature();...currentConditionsDisplay.update(temp,..);statisticsDisplay.update(temp,...)}









}

This is obviously contrary to the design principles of the previous blog: 1. For implementation programming, it will lead to a lot of code changes when modifying the bulletin board in the future. 2. The parts that will be changed are not encapsulated. When the requirements change in the future, the code will be implemented. a large number of replacements.

Since we are talking about the observer mode, this time we will go straight to the topic.

Observer Pattern: Defines a one-to-many dependency between objects, so that when an object changes state, all its dependents will be notified and automatically updated.

There is more than one way to implement the Observer pattern, but the most common is the class design that includes the Subject and Observer interfaces: the following is the class diagram of the above requirements



See the detailed code below:

Theme interface:

public interface Subject {
     //Used to register observers
 public void registerObserver(Observer o);
     //Delete observers
 public void removeObserver(Observer o);
     //When the state changes, call this method to make all observers notified
 public void notifyObservers();            
}

Observer interface:

public interface Observer {
    public void update(float temp,float humidity,float pressure);
}

Update the behavior interface (you can see why this interface is there later):

public interface DisplayElement {
    public void display();
}
 
 

Specific subject categories:

public class WeatherData implements Subject {
     //Define an array to record all observers
 private ArrayList observers ;
     private float temperature ;
     private float humidity ;
     private float pressure ;    

    public WeatherData(){
        observers=new ArrayList();
    }

    @Override
public void registerObserver(Observer o) {
        observers.add(o);    
    }

    @Override
public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if(i>=0){
            observers.remove(i);    
        }
    }

    // Traverse all observers and call their update method, which is to inform them of new data
 @Override
 public void notifyObservers() {
         for ( int i= 0 ;i< observers .size();i++){        
            Observer observer= (Observer) observers.get(i);
            observer.update(temperature,humidity,pressure);
        }
    }

    public void measurementsChanged(){
        notifyObservers();
    }

    //Used to simulate changing data
 public void setMeasurements( float temperature, float humidity, float pressure)    
    {
        this.temperature=temperature;
        this.humidity=humidity;
        this.pressure=pressure;
        measurementsChanged();
    }

The implementation class of a bulletin board:

public class CurrentConditionsDisplay implements Observer,DisplayElement {
    private float temperature;
    private float humidity;
    private  Subject weatherData;


    //Specify the Subject concrete class in the constructor and register it as an observer
 public   CurrentConditionsDisplay(Subject weatherData){
         this . weatherData =weatherData;    
        weatherData.registerObserver(this);
    }

    //The update method of the observer will be called passively in the observed class
 @Override
 public void update( float temp, float humidity, float pressure) {
         this . temperature =temp;
         this . humidity =humidity;        
        display();
    }

    //display method simulates displaying data
 @Override
 public void display() {        
        System.out.println("Current conditions:"+temperature+"F degrees and "+humidity+"humidity");
    }
}
Let's test the current weather condition billboard.

public static void main(String[] args) {
    WeatherData weatherData=new WeatherData();
    CurrentConditionsDisplay currentConditionsDisplay=new CurrentConditionsDisplay(weatherData);
    weatherData.setMeasurements(80,65,30.3f);
    weatherData.setMeasurements(82,63,40.1f);

}

result:

Current conditions:80.0F degrees and 65.0humidity

Current conditions:82.0F degrees and 63.0humidity

The program achieves our needs. When the data is newly set, the CurrentConditions notice board will update the displayed data in time;

Check out the program highlights below:

    The program objects we design are loosely coupled. The so-called loose coupling means that in a program, there should not be too many dependencies between various class instance objects. For example, in our program this time, when we have a When a new class is to be registered as an observer, the subject class does not need to modify its own code in order to be compatible with the new class, and it does not even need to care who is requesting it, and it does not matter whether the notification will be passed to the specific class that wants to register. For the observer object, as long as the Observer interface is implemented and the registration method is called, the subject class will send notifications to all objects that implement the Observer interface.

    The loosely coupled design makes our programs more resilient, minimizing dependencies between objects when dealing with changes, and minimizing the code that needs to be changed.

This is another of our design principles: strive for loosely coupled design between interacting objects.

In java, there are built-in observer pattern for us to use. Similar to the project example above, the difference is

1. The "subject" class extends from the ava.util.Observable class, and the observer implements the java.util.Observer interface. registerObserver in the example and

The removeObserver() method has been changed to addObserver and deleteObserver.

2. During data transfer, a method with parameters notofyObservers (Object arg) update (Observable o, object arg) is overloaded based on the data transfer method of our example.

When delivering notifications, any data object can be passed to each observer using the parameterized method.

3. A new setChanged() method has been added, protected synchronized void setChanged() { changed = true ;}


This method only changes the identifier of the global variable changed. The meaning of the changed variable is that every time the observer is notified, it will check whether the changed variable is true. If not, no notification will be sent. The significance of the setchanged method is that it can filter itself at certain times without sending notifications. For example, in our last example, the real situation is that a sensor accepts atmospheric data, rather than we set new data. When the amount of change in atmospheric data is particularly small, we want to ignore it to improve performance. So we can make some judgments and call setChanged when the changed value is higher than our minimum requirement. In this way, the notification can be sent successfully. Of course, after sending a comrade, set this flag to false.

Flaws of the built-in observer pattern

1. As mentioned above, the subject class extends from an Observable class, not an interface. Java does not allow multiple inheritance, and this goes against one of our design principles, resulting in extremely poor code reusability.

2. The setChanged method is protected, which means that unless you inherit Observable, you cannot create a new Observable instance and combine it into your own object, which violates one of our design principles.

So as long as you understand the idea of ​​the observer pattern, you can implement a set of observer patterns for use like the above example.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325611581&siteId=291194637