What is the observer model?
The Observer Pattern is also called Publish/Subscribe, Model/View, Source/Listener or Dependents. Define a one-to-many dependency where a topic object can be listened on by multiple observer objects at the same time, so that all dependent objects are notified and automatically updated whenever the state of the topic object changes. It belongs to the behavioral pattern.
The core of the observer mode is to decouple the observer from the observed, and link them with a mechanism similar to message/broadcast transmission, so that the changes of the observed can be notified to the interested observers, so as to make corresponding responses.
2. Application scenarios of observer mode
The observer mode is also widely used in real life, such as wake-up alarm, APP horn notification, email notification, broadcast notification, desktop application event response, etc.
In a software system, when the behavior of one party depends on the change of the behavior of the other party, the observer mode can be used to loosely coupling the two parties, so that the change of one party can be notified to the object of the other party who is interested in it, so that the object of the other party can respond to it. The Observer mode is applicable to the following application scenarios:
- When an abstract model contains two aspects, one of which depends on the other.
- Changes to one or more other objects depend on changes to another object.
- Realize functions similar to broadcast mechanism, do not need to know the specific receiver, just distribute the broadcast, the system interested objects will automatically receive the broadcast.
- Multiple levels of nesting are used to form a chain trigger mechanism that allows events to be notified across domains (across both observer types).
Roles involved in the observer model
Here is a common UML class diagram for the Observer pattern:
From the UML class diagram, we can see that the observer pattern consists of three main roles:
- Abstract Subject: an Observable that is being observed. This role is an abstract class or interface that defines methods for adding, deleting, and notifying observers of objects.
- ConcreteSubject: ConcreteSubject notifies registered observers when its internal state changes.
- Abstract Observer: Defines update methods that respond to notifications.
- ConcreteObserver: Automatically responds when receiving status updates.
Application of observer mode in business scenarios
When friends ask questions in the ecosystem, if there is a set of designated teachers to answer, the corresponding teachers will receive an email notification, which is an application scenario of the observer mode. Some of us might think of MQ, asynchronous queues, etc., but the JDK itself provides such apis. Let’s use code to restore such an application scenario.
1. Implement the observer mode based on the JDK built-in API
Create MPer class:
/** * the JDK provides an implementation of the observer, observed */
public class MPer extends Observable {
private String name = "MPer ecosphere";
private static MPer mPer = null;
private MPer(a) {}public static MPer getInstance(a) {
if (mPer == null) {
mPer = new MPer();
}
return mPer;
}
public String getName(a) {
return name;
}
public void publishQuestion(Question question) {
System.out.println(question.getUserName() + "In" + this.name + "A question was submitted on."); setChanged(); notifyObservers(question); }}Copy the code
Create a Question class:
@Data
public class Question {
private String userName;
private String content;
}
Copy the code
Create a Teacher class:
/** ** observer */
public class Teacher implements Observer {
private String name;
public Teacher(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
MPer mPer = (MPer) o;
Question question = (Question) arg;
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
System.out.println(name + "Hello, teacher! \n" + "You have received a message from" + mPer.getName() + ", hope you can answer the question as follows: \n" + question.getContent() + "\n" + "Questioner:"+ question.getUserName()); }}Copy the code
Client test code:
public class Test {
public static void main(String[] args) {
MPer mPer = MPer.getInstance();
Teacher mark = new Teacher("Mark");
Teacher zoe = new Teacher("Zoe");
mPer.addObserver(mark);
mPer.addObserver(zoe);
// Business logic code
Question question = new Question();
question.setUserName("Xiao Ming");
question.setContent("What scenarios does the observer model apply to?"); mPer.publishQuestion(question); }}Copy the code
The running results are as follows:
2. Easy landing observer mode based on Guava API
I recommend a very useful framework for implementing the observer pattern. Using the MAVEN API is also very simple, for example, to introduce the Maven dependency package:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
Copy the code
Create listening event GuavaEvent:
public class GuavaEvent {
@Subscribe
public void subscribe(String str) {
// Business logic
System.out.println(Execute the subscribe method, passing in the argument:+ str); }}Copy the code
Client test code:
public class Test {
public static void main(String[] args) {
EventBus eventBus = new EventBus();
GuavaEvent guavaEvent = new GuavaEvent();
eventBus.register(guavaEvent);
eventBus.post("Mark"); }}Copy the code
The running results are as follows:
3. Design the mouse event response API using the Observer pattern
Now let’s design a business scenario to help partners better understand the observer model. The observer mode is also used extensively in JDK source code. For example, java.awt.Event is one of the observer patterns, but Java is rarely used to write desktop programs. Let’s use our own code to implement it, to help friends more deeply understand the implementation principle of the observer mode. First, create the EventListener interface:
/** * observer abstraction */
public interface EventListener {}Copy the code
Create the Event class:
@Data
public class Event {
// The event source, by whom the action was issued
private Object source;
// The event is triggered, and who should be notified (the observer)
private EventListener target;
// The observer responds
private Method callback;
// The event name
private String trigger;
// Event trigger time
private long time;
public Event(EventListener target, Method callback) {
this.target = target;
this.callback = callback; }}Copy the code
Create the EventContext class:
/** ** The observed abstraction */
public class EventContext {
protected Map<String, Event> events = new HashMap<>();
public void addListener(String eventType, EventListener target, Method callback) {
events.put(eventType, new Event(target, callback));
}
public void addListener(String eventType, EventListener target) {
try {
this.addListener(eventType, target, target.getClass().getMethod("on" + toUpperFirstCase(eventType), Event.class));
} catch(Exception e) { e.printStackTrace(); }}private String toUpperFirstCase(String eventType) {
char[] chars = eventType.toCharArray();
chars[0] - =32;
return String.valueOf(chars);
}
private void trigger(Event event) {
event.setSource(this);
event.setTime(System.currentTimeMillis());
try {
if(event ! =null) {
// Call the callback function with reflectionevent.getCallback().invoke(event.getTarget(), event); }}catch(Exception e) { e.printStackTrace(); }}protected void trigger(String trigger) {
if (!this.events.containsKey(trigger)) {
return;
}
Event event = this.events.get(trigger); event.setTrigger(trigger); trigger(event); }}Copy the code
Create MouseEventType interface:
public interface MouseEventType {
/ / click
String ON_CLICK = "click";
/ / double
String ON_DOUBLE_CLICK = "doubleClick";
/ / bounce
String ON_UP = "up";
/ / press
String ON_DOWN = "down";
/ / move
String ON_MOVE = "move";
/ / rolling
String ON_WHEEL = "wheel";
/ / hover
String ON_OVER = "over";
/ / out of focus
String ON_BLUR = "blur";
/ / coke
String ON_FOCUS = "focus";
}
Copy the code
Create the Mouse class:
/** * The specific observed */
public class Mouse extends EventContext {
public void click(a) {
System.out.println("Call click method");
this.trigger(MouseEventType.ON_CLICK);
}
public void doubleClick(a) {
System.out.println("Call double click method");
this.trigger(MouseEventType.ON_DOUBLE_CLICK);
}
public void up(a) {
System.out.println("Call the pop-up method");
this.trigger(MouseEventType.ON_UP);
}
public void down(a) {
System.out.println("Call down method");
this.trigger(MouseEventType.ON_DOWN);
}
public void move(a) {
System.out.println("Call the move method");
this.trigger(MouseEventType.ON_MOVE);
}
public void wheel(a) {
System.out.println("Call the scroll method");
this.trigger(MouseEventType.ON_WHEEL);
}
public void over(a) {
System.out.println("Call hover method");
this.trigger(MouseEventType.ON_OVER);
}
public void blur(a) {
System.out.println("Call focus method");
this.trigger(MouseEventType.ON_BLUR);
}
public void focus(a) {
System.out.println("Call out-of-focus method");
this.trigger(MouseEventType.ON_FOCUS); }}Copy the code
Create the callback method MouseEventListener class:
public class MouseEventListener implements EventListener {
public void onClick(Event e) {
System.out.println("=========== Trigger mouse click event ============" + "\n" + e);
}
public void onDoubleClick(Event e) {
System.out.println("=========== Trigger the double mouse click event ============" + "\n" + e);
}
public void onUp(Event e) {
System.out.println("=========== Trigger mouse bouncing event ============" + "\n" + e);
}
public void onDown(Event e) {
System.out.println("=========== trigger mouse press event ============" + "\n" + e);
}
public void onMove(Event e) {
System.out.println("=========== trigger mouse movement event ============" + "\n" + e);
}
public void onWheel(Event e) {
System.out.println("=========== trigger mouse scroll event ============" + "\n" + e);
}
public void onOver(Event e) {
System.out.println("=========== trigger mouse hover event ============" + "\n" + e);
}
public void onBlur(Event e) {
System.out.println("=========== trigger out-of-focus event ============" + "\n" + e);
}
public void onFocus(Event e) {
System.out.println("=========== trigger mouse focus event ============" + "\n"+ e); }}Copy the code
Client test code:
public class Test {
public static void main(String[] args) {
MouseEventListener listener = new MouseEventListener();
Mouse mouse = newMouse(); mouse.addListener(MouseEventType.ON_CLICK, listener); mouse.addListener(MouseEventType.ON_MOVE, listener); mouse.click(); mouse.move(); }}Copy the code
Advantages and disadvantages of the observer model
Advantages:
- The observer and the observed are loosely coupled (abstractly coupled) in accordance with the dependency inversion principle.
- The presentation layer (observer) and the data logic layer (observed) are separated, and a set of trigger mechanism is established, so that the change of data can respond to multiple presentation layers.
- One to many communication mechanism is implemented, event registration mechanism is supported, interest distribution mechanism is supported, when the observer triggers the event, only interested observers can receive the notification.
Disadvantages:
- Event notification can take a long time if there are too many observers.
- Event notification is linear. If one observer processes an event, it will affect subsequent observers to receive the event.
- If there is a circular dependency between the observer and the observed, it may cause circular calls between the two, causing the system to crash.
Six, friendship links
Design Patterns – Factory Patterns learning tour
Design Patterns – a learning tour of singleton patterns
Design Patterns – A learning journey of prototyping patterns
Design Patterns – Builder patterns learning tour
Design Patterns – Agent patterns learning tour
Design Patterns – A learning tour of facade patterns
Design Patterns – A learning tour of decorator patterns
Design Patterns – Enjoy yuan patterns learning journey
Design Patterns – A learning journey of composite patterns
Design Patterns – Adapter patterns learning journey
Design Patterns – Bridge patterns learning journey
Design Patterns – Delegation patterns learning journey
Design Patterns – a template method pattern learning journey
Design Patterns – A learning journey of Strategic patterns
Design Patterns – A learning journey of chain of Responsibility patterns
Design Patterns – An iterator pattern learning journey
Design Mode – Command mode learning tour
Design pattern-state pattern learning journey
Design Patterns – Memo patterns learning journey
Design Patterns – A learning journey through the Mediator pattern
Welcome to follow the wechat public account (MarkZoe) to learn from and communicate with each other.