Do you still remember how the gangsters cooperated in the police and gangster film? When a gang is burglary, one or two people always take the wind at the door. If there is any movement, the accomplices inside will be notified immediately to retreat urgently. Perhaps the person who lets the news does not necessarily know every accomplice in it; and there may be a new younger brother who doesn't know the one who lets the news. But this is nothing, it cannot affect their communications because they have a code that has been agreed upon.
Haha, the relationship between the air venter and the thief mentioned above is a living example of the observer pattern in reality.
Observer mode is also known as Publish/Subscribe mode. GOF defines the observer pattern as follows: defines a one-to-many dependency between objects. When the state of an object changes, all objects that depend on it are notified and automatically updated.
Here I will first talk about an important principle of object-oriented design - the single responsibility principle. Therefore, each object of the system should focus on discrete abstractions in the problem domain. Therefore, ideally, an object only does one thing. This brings many benefits in development: it provides reusability and maintenance, and is also a good foundation for refactoring.
Therefore, almost all design patterns are based on this basic design principle. I think the origin of the observer model should be in the processing of GUI and business data, because most of the examples explaining the observer model now are this topic. However, the application of the observer mode is by no means limited to this aspect.
Well, the understanding of definition always requires instances to analyze. WeChat service accounts are quite popular nowadays. Let’s introduce the observer model to you with the background of WeChat service accounts.
Look at a picture:
Each user has 3 lines in the above picture, which are omitted in order to make the picture clear.
As shown in the picture above, the service number is our theme and the user is the observer. Now we clarify the following functions:
1. Service account is the theme, and business is pushing messages
2. Observers only need to subscribe to the topic, and they will be sent as soon as there is new news.
3. Unsubscribe when you don't want this topic message
4. As long as the service account is still there, someone will always subscribe. Now let’s take a look at the class diagram of the observer pattern:
Next is the code time, we simulate a WeChat 3D lottery service account and some subscribers.
First, start writing about our topic interface and observer interface:
package com.zhy.pattern.observer; /** * Topic interface, all topics must implement this interface* * @author zhy * */ public interface Subject { /** * Register an observer* * @param observer */ public void registerObserver(Observer observer); /** * Remove an observer* * @param observer */ public void removeObserver(Observer observer); /** * Notify all observers*/ public void notifyObservers(); } package com.zhy.pattern.observer; /** * @author zhy All observers need to implement this interface*/ public interface Observer { public void update(String msg); }Next 3D service number implementation class:
package com.zhy.pattern.observer; import java.util.ArrayList; import java.util.List; public class ObjectFor3D implements Subject { private List<Observer> observers = new ArrayList<Observer>(); /** * 3D lottery number*/ private String msg; @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { int index = observers.indexOf(observer); if (index >= 0) { observers.remove(index); } } @Override public void notifyObservers() { for (Observer observer: observers) { observer.update(msg); } } /** * Topic update message* * @param msg */ public void setMsg(String msg) { this.msg = msg; notifyObservers(); } }Simulate two users:
package com.zhy.pattern.observer; public class Observer1 implements Observer { private Subject subject; public Observer1(Subject subject) { this.subject = subject; subject.registerObserver(this); } @Override public void update(String msg) { System.out.println("observer1 Gets the 3D number -->" + msg + ", I want to write it down."); } } package com.zhy.pattern.observer; public class Observer2 implements Observer { private Subject subject ; public Observer2(Subject subject) { this.subject = subject ; subject.registerObserver(this); } @Override public void update(String msg) { System.out.println("observer2 Gets the 3D number -->" + msg + "I want to tell my roommates."); } } It can be seen that all users who subscribe to messages to it are maintained in the service account, and all users are notified when there is a new message in the service account. The entire architecture is a loose coupling, and the implementation of the theme does not depend on the user. When a new user is added, the code of the theme does not need to be changed; how the user processes the obtained data has nothing to do with the theme;
Finally, look at the test code:
package com.zhy.pattern.observer.test; import com.zhy.pattern.observer.ObjectFor3D; import com.zhy.pattern.observer.Observer; import com.zhy.pattern.observer.Observer1; import com.zhy.pattern.observer.Observer2; import com.zhy.pattern.observer.Subject; public class Test { public static void main(String[] args) { //Simulate a 3D service number ObjectFor3D subjectFor3d = new ObjectFor3D(); //Customer1 Observer observer1 = new Observer1(subjectFor3d); Observer observer2 = new Observer2(subjectFor3d); subjectFor3d.setMsg("20140420's 3D number is: 127"); subjectFor3d.setMsg("20140421's 3D number is: 333"); } }Output result:
observer1 gets the 3D number -->20140420's 3D number is: 127, I want to write it down. observer2 gets the 3D number -->20140420's 3D number is: 127 I want to tell my roommates. observer1 gets the 3D number -->20140421's 3D number is: 333, I want to write it down. observer2 gets the 3D number -->20140421's 3D number is: 333 I want to tell my roommates.
There are many places in JDK or Andorid that implement the observer mode, such as XXXView.addXXXListenter . Of course, XXXView.setOnXXXListener is not necessarily an observer mode, because the observer mode is a one-to-many relationship. For setXXXListener, it is a 1-to-1 relationship, and it should be called a callback.
Congratulations on learning the observer mode. The above observer mode allows us to write it out from scratch. Of course, Java has helped us implement the observer mode, with the help of java.util.Observable and java.util.Observer.
Below we use Java built-in classes to implement the observer pattern:
First of all, there is a 3D lottery service number theme:
package com.zhy.pattern.observer.java; import java.util.Observable; public class SubjectFor3d extends Observable { private String msg ; public String getMsg() { return msg; } /** * Topic update message* * @param msg */ public void setMsg(String msg) { this.msg = msg ; setChanged(); notifyObservers(); } }The following is the theme of a Double Color Ball service number:
package com.zhy.pattern.observer.java; import java.util.Observable; public class SubjectForSSQ extends Observable { private String msg ; public String getMsg() { return msg; } /** * Topic update message* * @param msg */ public void setMsg(String msg) { this.msg = msg ; setChanged(); notifyObservers(); } }Finally, our users:
package com.zhy.pattern.observer.java; import java.util.Observable; import java.util.Observer; public class Observer1 implements Observer { public void registerSubject(Observable observable) { observable.addObserver(this); } @Override public void update(Observable o, Object arg) { if (o instanceof SubjectFor3d) { SubjectFor3d subjectFor3d = (SubjectFor3d) o; System.out.println("subjectFor3d's msg -->" + subjectFor3d.getMsg()); } if (o instanceof SubjectForSSQ) { SubjectForSSQ subjectForSSQ = (SubjectForSSQ) o; System.out.println("subjectForSSQ's msg -->" + subjectForSSQ.getMsg()); } } }Look at a test code:
package com.zhy.pattern.observer.java; public class Test { public static void main(String[] args) { SubjectFor3d subjectFor3d = new SubjectFor3d() ; SubjectForSSQ subjectForSSQ = new SubjectForSSQ() ; Observer1 observer1 = new Observer1(); observer1.registerSubject(subjectFor3d); observer1.registerSubject(subjectForSSQ); subjectFor3d.setMsg("hello 3d'nums : 110 "); subjectForSSQ.setMsg("ssq'nums : 12,13,31,5,4,3 15"); } }Test results:
subjectFor3d's msg -->hello 3d'nums : 110 subjectForSSQ's msg -->ssq'nums : 12,13,31,5,4,3 15
It can be seen that using Java built-in classes to implement the observer pattern, the code is very concise. By the way, addObserver, removeObserver, notifyObservers have been implemented for us. All we can see that Observable is a class, not an interface. Basically, the book has a negative attitude towards Java's design. It feels that Java's built-in observer pattern violates the principle of interface-oriented programming. However, if you think about it, you are indeed writing the observer pattern here (our own implementation). The interface idea is very good, but if you continue to add many topics now, the ddObserver, removeObserver, notifyObservers for each topic are basically the same. Interfaces cannot implement code reuse, and there is no way to use the combined mode to achieve the reuse of these three methods, so I think it is reasonable to implement these three methods in the class here.