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.
This is also true in the software world. For example, the relationship between data in Excel and line chart, pie chart and histogram; The relationship between model and view in MVC mode; Event source and event handler in the event model. All this is very convenient if implemented in observer mode.
Definition and characteristics of pattern
The definition of Observer mode: it means that there is a one to many dependency between multiple objects. When the state of an object changes, all objects that depend on it are notified and automatically updated. 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.
Structure and implementation of pattern
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.
1. Structure of the model
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.
The structure of observer mode is shown in Figure 1.
Fig. 1 structure diagram of observer mode
2. Implementation of mode
The implementation code of observer mode is as follows:
package net.biancheng.c.observer; import java.util.*; public class ObserverPattern { public static void main(String[] args) { Subject subject = new ConcreteSubject(); Observer obs1 = new ConcreteObserver1(); Observer obs2 = new ConcreteObserver2(); subject.add(obs1); subject.add(obs2); subject.notifyObserver(); } } //Abstract goal abstract class Subject { protected List<Observer> observers = new ArrayList<Observer>(); //Add observer method public void add(Observer observer) { observers.add(observer); } //Delete observer method public void remove(Observer observer) { observers.remove(observer); } public abstract void notifyObserver(); //Method of notifying the observer } //Specific objectives class ConcreteSubject extends Subject { public void notifyObserver() { System.out.println("The specific objectives have changed..."); System.out.println("--------------"); for (Object obs : observers) { ((Observer) obs).response(); } } } //Abstract observer interface Observer { void response(); //reaction } //Specific observer 1 class ConcreteObserver1 implements Observer { public void response() { System.out.println("Specific observer 1 responds!"); } } //Specific observer 1 class ConcreteObserver2 implements Observer { public void response() { System.out.println("Specific observer 2 responds!"); } }
The running results of the program are as follows:
The specific objectives have changed -------------- Specific observer 1 responds! Specific observer 2 responds!
Application scenario of pattern
In a software system, when one party's behavior depends on the change of the other party's behavior, the observer mode can be used to loosely couple the two sides, so that the change of one party can be notified to the interested object of the other party, so that the object of the other party can respond to it.
Through the previous analysis and application examples, it can be seen that the observer mode is suitable for the following situations.
- There is a one to many relationship between objects. The change of the state of one object will affect other objects.
- When an abstract model has two aspects, one of which depends on the other, they can be encapsulated in independent objects so that they can be changed and reused independently.
- To realize the function similar to the broadcast mechanism, you don't need to know the specific listener, you just need to distribute the broadcast, and the interested objects in the system will automatically receive the broadcast.
- Multi level nesting is used to form a chain trigger mechanism, so that events can be notified across domains (across two observer types).
Mode extension
stay Java Observer mode is defined through java.util.Observable class and java.util.Observer interface. As long as their subclasses are implemented, observer mode instances can be written.
1. Observable class
Observable class is an abstract target class. It has a Vector vector to store all observer objects to be notified. The following describes its three most important methods.
- void addObserver(Observer o) method: used to add a new observer object to the vector.
- void notifyObservers(Object arg) method: call the update() method of all observer objects in the vector to notify them of data changes. Usually, the later the observer joins the vector, the earlier he is notified.
- void setChange() method: used to set an internal flag bit of boolean type to indicate that the target object has changed. notifyObservers() notifies the observer when it is true.
2. Observer interface
The Observer interface is an abstract Observer. It monitors the changes of the target object. When the target object changes, the Observer is notified and calls the void update(Observable o,Object arg) method to perform corresponding work.
[example 3] an example of Observer mode of crude oil futures using Observable class and Observer interface.
Analysis: when the crude oil price rises, the air side is sad and many parties are happy; When oil prices fell, the short side was happy and many parties were sad. The abstract target class in this example has been defined in Java, and its subclass can be directly defined, that is, the oil futures class. It is a specific target class. In this class, a SetPriCe(float price) method is defined. When the crude oil data changes, the notifyObservers(Object arg) method of its parent class is called to notify all observers; In addition, the abstract observer interface (observer) in this example has been defined in Java. Just define its subclasses, that is, the specific Observer class (including multi-party class Bull and empty party class Bear), and implement the update(Observable o,Object arg) method. Figure 5 shows its structure.
Figure 5 structure diagram of observer mode example of crude oil futures
The program code is as follows:
package net.biancheng.c.observer; import java.util.Observer; import java.util.Observable; public class CrudeOilFutures { public static void main(String[] args) { OilFutures oil = new OilFutures(); Observer bull = new Bull(); //Many parties Observer bear = new Bear(); //Empty square oil.addObserver(bull); oil.addObserver(bear); oil.setPrice(10); oil.setPrice(-8); } } //Specific target category: crude oil futures class OilFutures extends Observable { private float price; public float getPrice() { return this.price; } public void setPrice(float price) { super.setChanged(); //Set the internal flag bit to indicate that the data has changed super.notifyObservers(price); //Inform the observer that the price has changed this.price = price; } } //Specific observers: multiple class Bull implements Observer { public void update(Observable o, Object arg) { Float price = ((Float) arg).floatValue(); if (price > 0) { System.out.println("Rising oil prices" + price + "Yuan, happy!"); } else { System.out.println("Falling oil prices" + (-price) + "Yuan, I'm sad!"); } } } //Specific observers: empty side class Bear implements Observer { public void update(Observable o, Object arg) { Float price = ((Float) arg).floatValue(); if (price > 0) { System.out.println("Rising oil prices" + price + "Yuan, the empty side is sad!"); } else { System.out.println("Falling oil prices" + (-price) + "Yuan, the air side is happy!"); } } }
The running results of the program are as follows:
The oil price rose by 10.0 yuan, and the air side was sad! The oil price has risen by 10.0 yuan. Many parties are happy! The oil price fell by 8.0 yuan, and the air side was happy! The oil price fell by 8.0 yuan, and many parties were sad!
extended reading
If you want to understand the application of observer mode in real projects, you can swipe to read Implementation of notification mechanism based on Java API article.