Design Pattern-Observer pattern with Java)

Source: Internet
Author: User

Overview

The observer mode (sometimes referred to as the publish/subscribe mode) is a software design mode. In this mode, a target object manages all observer objects that depend on it and actively sends notifications when its status changes. This is usually done by calling the methods provided by various observers. This mode is usually used to implement an event processing system.

 

Let's look at an example.

A child is sleeping and needs to be fed after waking up.

We use Java, so don't make the following jokes (dressed in Object-Oriented processes ):

Public class simulation {public static void main (string... ARGs) {// when the child goes to bed // after the child gets up, his father feeds the milk //...}}

 

Based on the object-oriented thinking and the multi-thread simulation of child and Dad, the child is sleeping and can get up at any time. Dad checks whether the child wakes up after a while.

package observer;import java.util.Random;class Child implements Runnable {public static Random r = new Random();private boolean wake = false;public Child() {new Thread(this).start();}@Overridepublic void run() {while (!wake) {System.out.println("Child:I am sleeping...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}if (r.nextInt(10) > 8) {wakeUp();}}}public void wakeUp() {wake = true;}public boolean isWake() {return wake;}}class Dad implements Runnable {private Child c;public Dad(Child c) {new Thread(this).start();this.c = c;}@Overridepublic void run() {while (!c.isWake()) {System.out.println("Dad:child is sleeping...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}feed(c);}private void feed(Child c2) {System.out.println("feed child!");}}public class FirstQuestion {public static void main(String[] args) {new Dad(new Child());}}

In this way, functions can be implemented, but resources are wasted. With this multi-thread enabled, Dad spent all its time watching the children. Dad's plan to play cards in the afternoon was ruined. We can easily release dad:

class Child implements Runnable {public static Random r = new Random();private Dad d;private boolean wake = false;public Child(Dad d) {this.d = d;}@Overridepublic void run() {while (!wake) {System.out.println("Child:I am sleeping...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}if (r.nextInt(10) > 8) {wakeUp();}}}public void wakeUp() {wake = true;d.feed(this);}public boolean isWake() {return wake;}}class Dad {public void feed(Child c) {System.out.println("feed child!");}}public class FirstQuestion {public static void main(String[] args) {new Thread(new Child(new Dad())).start();}}

In this way, the functions have basically been implemented. If we want to know when the child will wait for some information, it is not appropriate to write it in the Child class, so we abstract the wakenupevent in the class:

class WakenUpEvent {private Date date;private String loc;private Dad dad;public WakenUpEvent(Date date, String loc, Dad dad) {super();this.date = date;this.loc = loc;this.dad = dad;}}class Child implements Runnable {private Dad d;public Child(Dad d) {this.d = d;}@Overridepublic void run() {try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}wakeUp();}public void wakeUp() {d.actionToWakenUp(new WakenUpEvent(new Date(), "child", d));}}class Dad {public void actionToWakenUp(WakenUpEvent wakenUpEvent) {System.out.println("child feed!");}}public class FirstQuestion {public static void main(String[] args) {new Thread(new Child(new Dad())).start();}}

 

In this way, Dad can do his own thing, as long as you hear the voice of the child, come and feed. It seems that the problem has been solved. If the child wakes up, the child's grandfather wants to hug it, and the child's puppy wants to scream, and so on, if according to the above design, the child needs to hold reference from Grandpa grandfather, dog, and so on, and then call the response processing method... A large length needs to be modified. In fact, we can use a set of children to store all the objects listening to children. When a child wakes up, the Child calls the listener Processing Method in sequence. To implement a unified interface that can be referenced and called by the Child listener set, we use the interface.

class WakenUpEvent {private Date date;private String eventType;private Object source;public WakenUpEvent(Date date, String eventType, Object source) {this.date = date;this.eventType = eventType;this.source = source;}}class Child implements Runnable {private List<WakenUpListener> list = new ArrayList<WakenUpListener>();public void addWakenUpListener(WakenUpListener l) {list.add(l);}@Overridepublic void run() {System.out.println("child is sleeping...");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}wakeUp();}public void wakeUp() {for (WakenUpListener l : list) {l.actionWakenUp(new WakenUpEvent(new Date(), "", this));}}}interface WakenUpListener {void actionWakenUp(WakenUpEvent e);}class Dad implements WakenUpListener {@Overridepublic void actionWakenUp(WakenUpEvent e) {System.out.println("dad feed child!");}}class GrandFather implements WakenUpListener {@Overridepublic void actionWakenUp(WakenUpEvent e) {System.out.println("grandfather holl child!");}}public class FirstQuestion {public static void main(String[] args) {Child c = new Child();c.addWakenUpListener(new Dad());c.addWakenUpListener(new GrandFather());new Thread(c).start();}}

 

Now let's take a look at the summary example. It's easy to understand!

Defines a one-to-many dependency between objects. When the status of an object changes, all objects dependent on it are notified and automatically updated. [Gof design patterns]

 

In observer ModePush mode and pull mode[Excerpt]

In the observer mode, the push mode and pull mode are distinguished. The difference between the two is briefly explained: when there is a message, the push mode transmits the message information in the form of parameters (push) for all observers, the PULL mode is that when there is a message, the method of notifying the message itself does not contain any parameters, and the observer himself gets (pulls) the message from the subject object. With this in mind, you may find that the above example is actually an observer mode of Push mode. Let's first look at the benefits of this mode: when there is a message, all the observers will directly get all the messages and process the corresponding programs, which has nothing to do with the subject object, the relationship between the two is a loose coupling. However, it also has defects. First, all observers obtain the same message. Maybe some information cannot be used at all for a certain observer, that is, the observer cannot "obtain as needed "; second, when the parameter of the notification message changes, all the observer objects must change. In view of the above problems, the PULL mode came into being. The observer takes the initiative to retrieve the message and can retrieve the message according to the information required. It does not get all the message parameters as in the push mode. OK. Do you have some knowledge about the push and pull modes?

In fact, in the above Code, due to the impact of the AWT event in Java, I added the source field to the event, which is a manifestation of the PULL mode. We can get public event information, or get event object information through source.

 

AWT Event Simulation

Speaking of AWT events, we simulate AWT event processing based on the above ideas. The observer mode makes AWT event functions simpler and more elegant. However, the true AWT also requires the support of event-driven windows, for example, if you press a button, first capture the message in windows and distribute the message to the Java Virtual Machine. The virtual machine calls the corresponding processing button and the button calls the listener for processing (personal understanding ). Generally, AWT event processing:

public class AwtButton extends Frame {public void lanch() {Button b = new Button("test");b.addActionListener(new MyActionListener());b.addActionListener(new MyActionListener1());this.add(b);this.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});setSize(100, 100);setVisible(true);}public static void main(String[] args) {new AwtButton().lanch();}class MyActionListener implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("button pressed!");}}class MyActionListener1 implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("button pressed1!");}}}

 

Combined with the above child example, we use the console to simulate the AWT event:

public class SimulationAwtButton {public static void main(String[] args) {Button b = new Button();b.addActionListener(new MyActionListener1());b.addActionListener(new MyActionListener2());b.pressed();}}class Button {private List<ActionListener> list = new ArrayList<ActionListener>();public void addActionListener(ActionListener l) {list.add(l);}public void pressed() {ActionEvent e = new ActionEvent(this);for(ActionListener l : list) {l.actionPerform(e);}}}interface ActionListener {void actionPerform(ActionEvent e) ;}class ActionEvent {private long time;private Object source;public ActionEvent(Object source) {this.time = System.currentTimeMillis();this.source = source;}public long getTime() {return time;}public Object getSource() {return source;}}class MyActionListener1 implements ActionListener {@Overridepublic void actionPerform(ActionEvent e) {System.out.println("SimulationButton ActionPerformed:" +e.getTime() + e.getSource());}}class MyActionListener2 implements ActionListener {@Overridepublic void actionPerform(ActionEvent e) {System.out.println("SimulationButton ActionPerformed:" +e.getTime() + e.getSource());}}

 

In this way, we have a deeper understanding of Java AWT event processing.

 

Applicability

1. When an abstract model has two aspects, one of which depends on the other. Encapsulate the two in independent objects so that they can be changed and reused independently.

2. When changing an object, you need to change other objects at the same time without knowing how many objects need to be changed.

3. When an object must notify other objects, it cannot assume who the other objects are. In other words, you do not want these objects to be tightly coupled.

Summary

In the observer mode, the notification dependency between one-to-multiple objects is loose, the maintainability and scalability of the program are greatly improved, and the open-closed principle is well met.

References

. Net Design Pattern (19): Observer pattern (partial Excerpt from the original article)

Java Shang xuexiang Ma soldiers Design Mode

Baidu Encyclopedia: Observer Mode

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.