1, Foreword
In the real world, many objects do not exist independently, and the behavior change of one object may lead to the behavior change of one or more other objects. For example, when the price of a commodity rises, some businesses will be happy and consumers will be sad; Also, when we drive to the intersection, we will stop at the red light and go at the green light. There are many examples, such as stock prices and stock market, WeChat official account and WeChat users, weather bureau weather forecast and listeners, thieves and police.
1.1 project requirements of weather forecast
The specific requirements for the weather forecast project are as follows:
- The weather station can publish the daily measured temperature, humidity, air pressure, etc. in the form of announcement (such as to its own website or a third party).
- An open API needs to be designed so that other third parties can access the weather station to obtain data.
- Provide interfaces for temperature, air pressure and humidity.
- When the measurement data is updated, it shall be able to notify the third party in real time.
1.2 common solutions to solve the problem of weather forecast demand
Through the analysis of the weather station project, we can preliminarily design a WeatherData class.
explain:
- Through the getXxx method, the third party can access and obtain relevant information;
- When the data is updated, the weather station updates the data by calling dataChange(). When the third party obtains it again, it can get the latest data. Of course, it can also be pushed.
The specific code is as follows:
public class Client { public static void main(String[] args) { //Create accessor currentConditions CurrentConditions currentConditions = new CurrentConditions(); //Create WeatherData and pass the access party currentConditions to WeatherData WeatherData weatherData = new WeatherData(currentConditions); //Update weather conditions weatherData.setData(30, 150, 40); //Changes in weather conditions System.out.println("============Changes in weather conditions============="); weatherData.setData(40, 160, 20); } } public class WeatherData { private float temperatrue; private float pressure; private float humidity; private CurrentConditions currentConditions; //Join a new third party public WeatherData(CurrentConditions currentConditions) { this.currentConditions = currentConditions; } public float getTemperature() { return temperatrue; } public float getPressure() { return pressure; } public float getHumidity() { return humidity; } public void dataChange() { //Call the access Party's update currentConditions.update(getTemperature(), getPressure(), getHumidity()); } //When the data is updated, setData is called public void setData(float temperature, float pressure, float humidity) { this.temperatrue = temperature; this.pressure = pressure; this.humidity = humidity; //Call dataChange to push the latest information to the access party currentConditions dataChange(); } } /** * Display the current weather (it can be understood as the weather station's own website) * @author Administrator * */ public class CurrentConditions { // Temperature, air pressure, humidity private float temperature; private float pressure; private float humidity; //Weather update is called by WeatherData. I use push mode public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; display(); } //display public void display() { System.out.println("***Today mTemperature: " + temperature + "***"); System.out.println("***Today mPressure: " + pressure + "***"); System.out.println("***Today mHumidity: " + humidity + "***"); } }
Problem analysis:
- Access of other third parties to meteorological stations to obtain data;
- Unable to dynamically add a third party (Sina website) at runtime;
- Violation of ocp principle = > observer mode;
2, Observer mode
Definition of observer mode: it refers to the one to many dependency relationship between multiple objects. When the state of an object changes, all objects that depend on it can be notified and updated automatically. This mode is sometimes called publish subscribe mode and model view mode. It is an object behavior mode.
Observer mode is an object behavior mode, and its main advantages are as follows.
- It reduces the coupling relationship between the target and the observer, which is an abstract coupling relationship. Comply with the principle of dependency inversion.
- A trigger mechanism is established between the target and the observer.
Its main disadvantages are as follows.
- The dependency between the target and the observer is not completely removed, and circular references may occur.
- When there are many observers, the announcement takes a lot of time, which affects the efficiency of the program.
2.1 structure and implementation principle of mode
When implementing observer mode, it should be noted that the specific target object and the specific observer object cannot be called directly, otherwise they will be closely coupled, which violates the object-oriented design principle.
The main roles of the observer model are as follows.
- Abstract Subject role: also known as abstract target class, it provides an aggregation class for saving observer objects, methods for adding and deleting observer objects, and abstract methods for notifying all observers.
- Concrete subject role: also known as concrete target class, it implements the notification method in the abstract target. When the internal state of the concrete subject changes, it notifies all registered observer objects.
- Abstract Observer role: it is an abstract class or interface, which contains an abstract method to update itself. It is called when receiving the change notification of a specific topic.
- Concrete Observer role: implement the abstract method defined in the abstract observer to update its status when notified of the change of the target.
As shown in the figure below:
2.2 observer model to solve the problem of weather forecast demand
The specific code is as follows:
public class Client { public static void main(String[] args) { // TODO Auto-generated method stub //Create a WeatherData WeatherData weatherData = new WeatherData(); //Create observer CurrentConditions currentConditions = new CurrentConditions(); BaiduSite baiduSite = new BaiduSite(); //Register to weatherData weatherData.registerObserver(currentConditions); weatherData.registerObserver(baiduSite); //test System.out.println("Notify each registered observer, Look at the information"); weatherData.setData(10f, 100f, 30.3f); weatherData.removeObserver(currentConditions); //test System.out.println(); System.out.println("Notify each registered observer, Look at the information"); weatherData.setData(10f, 100f, 30.3f); } } //Interface, let WeatherData implement it public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } /** * Class is the core * 1. Contains the latest weather information * 2. Contains a collection of observers, managed using ArrayList * 3. When the data is updated, it will actively call ArrayList and notify all (access parties) to see the latest information * * @author maoqichuan */ public class WeatherData implements Subject { private float temperatrue; private float pressure; private float humidity; //Observer set private ArrayList<Observer> observers; //Join a new third party public WeatherData() { observers = new ArrayList<Observer>(); } public float getTemperature() { return temperatrue; } public float getPressure() { return pressure; } public float getHumidity() { return humidity; } public void dataChange() { //Call the access Party's update notifyObservers(); } //When the data is updated, setData is called public void setData(float temperature, float pressure, float humidity) { this.temperatrue = temperature; this.pressure = pressure; this.humidity = humidity; //Call dataChange to push the latest information to the access party currentConditions dataChange(); } //Register an observer @Override public void registerObserver(Observer o) { // TODO Auto-generated method stub observers.add(o); } //Remove an observer @Override public void removeObserver(Observer o) { // TODO Auto-generated method stub if (observers.contains(o)) { observers.remove(o); } } //Traverse all observers and notify @Override public void notifyObservers() { // TODO Auto-generated method stub for (int i = 0; i < observers.size(); i++) { observers.get(i).update(this.temperatrue, this.pressure, this.humidity); } } } //Observer interface, implemented by observers public interface Observer { void update(float temperature, float pressure, float humidity); } public class CurrentConditions implements Observer { // Temperature, air pressure, humidity private float temperature; private float pressure; private float humidity; // Weather update is called by WeatherData. I use push mode public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; display(); } // display public void display() { System.out.println("***Today mTemperature: " + temperature + "***"); System.out.println("***Today mPressure: " + pressure + "***"); System.out.println("***Today mHumidity: " + humidity + "***"); } } // Specific observer public class BaiduSite implements Observer { // Temperature, air pressure, humidity private float temperature; private float pressure; private float humidity; // Weather update is called by WeatherData. I use push mode public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; display(); } // display public void display() { System.out.println("===Baidu website===="); System.out.println("***Baidu website temperature : " + temperature + "***"); System.out.println("***Baidu website pressure: " + pressure + "***"); System.out.println("***Baidu website humidity: " + humidity + "***"); } }
The specific operation results are as follows:
"C:\Program Files (x86)\Java\jdk1.8.0_151\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar=51690:C:\Program Files\JetBrains\IntelliJ IDEA 2020.2.3\bin" -Dfile.encoding=GBK -classpath "D:\yingzi\study\Source code\B Station design mode courseware\Source note courseware\code\DesignPattern\bin;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_151\jre\lib\rt.jar;D:\yingzi\study\Source code\B Station design mode courseware\Source note courseware\code\DesignPattern\src\com\atguigu\proxy\cglib\asm-commons.jar;D:\yingzi\study\Source code\B Station design mode courseware\Source note courseware\code\DesignPattern\src\com\atguigu\proxy\cglib\asm-tree.jar;D:\yingzi\study\Source code\B Station design mode courseware\Source note courseware\code\DesignPattern\src\com\atguigu\proxy\cglib\asm.jar;D:\yingzi\study\Source code\B Station design mode courseware\Source note courseware\code\DesignPattern\src\com\atguigu\proxy\cglib\cglib-2.2.jar" com.atguigu.observer.improve.Client Notify each registered observer, Look at the information ***Today mTemperature: 10.0*** ***Today mPressure: 100.0*** ***Today mHumidity: 30.3*** ===Baidu website==== ***Baidu website temperature : 10.0*** ***Baidu website pressure: 100.0*** ***Baidu website humidity: 30.3*** Notify each registered observer, Look at the information ===Baidu website==== ***Baidu website temperature : 10.0*** ***Baidu website pressure: 100.0*** ***Baidu website humidity: 30.3*** The process has ended,Exit code 0
2.3 use of observer mode in JDK source code
The Observable class of Jdk uses the observer mode. Its role analysis is as follows:
- The function and status of Observable are equivalent to the Subject we talked about earlier;
- Observable is a class, not an interface. The core method has been implemented in the class, that is, the method of managing Observer add.. delete.. notify;
- The function and status of Observer are equivalent to those of Observer mentioned earlier, including update;
- The use methods of Observable and Observer are the same as those mentioned above, except that Observable is a class that implements the Observer mode through inheritance;