1. Problem
This is often encountered when you do an interface before: I hope to keep each independent component (class), but I hope that they can communicate with each other. For example, Explorer in Windows, we hope that the mouse click on the left is a node of the tree directory, and the file browsing on the right will list the files and subdirectories in the node directory, similar to such a simple application, if only one class inherits JFrame, The tree assembly and the panel of the browsing file are as a member, just like:
Public Class Mainframe Extends Jframe
{
JPANel Treepanel;
JTree Tree;
JPanel FilePanel;
...
}
This is of course easily transmitted between the two, but the scalability is poor. It is often easy to think of two ways: retaining a member of another component type in a component, initialization, is incorporated as a parameter, such as:
Class Treepanel Extends JPanel
{
JTree Tree;
...
}
Class FilePanel Extends JPanel
{
Public FilePanel (JTREE TREE) {...}
...
}
Or thread a component, keep monitoring the change in another component, and then make a corresponding reflection, such as:
Class Treepanel Extends JPanel
{
JTree Tree;
...
}
Class FilePanel Extends JPanel IMPLEMENTS RUNNABLE
{
Public void Run ()
{
While (True)
{
// Listen to the change of TREE
}
...
}
...
}
This can indeed reach our goal, but the first program is clearly not conducive to loose coupling, and the second solution compares system resources. Through learning design patterns, we find that you can use Observer mode to solve this problem. 2. Observer mode design mode is divided into creation, structural and behavior, where behavior patterns dealt with inter-object communication, designated interactive mode, etc., OBServer mode is a design pattern that belongs to behavior. Follow the "Gang of Four" in "Design Patterns" defined a one-to-many dependency between the objects, and all objects depend on it when the status of an object changes. Notification and automatically update ", this description is just in line with our needs of" component communication ". Let's take a look at the structure of the OBServer mode: The meaning of each element is as follows:
Subject: Abstract interface for observed targets, provides registration, logout service, and notify method for Observer, notification Observer target changes; Object: Observer's abstract interface, UPDATE method is a notification of changes in Subject status The action to be taken afterwards; ConcreteSubject: Subject specific implementation; ConcreteObserver: OBServer's specific implementation OBServer mode is very useful when implementing the MVC structure, and decoupled for data and data. 3. Observer mode in Java: Observer and Observable after approving the description of the Observer mode, now we are more concerned about how it is applied in Java. Fortunately, since JDK 1.0, there is an API dedicated to this application, which is the OBServer interface and the OBSERVABLE class, which is part of the java.util package. It seems that Java's developers are really a designed pattern, while Java is indeed born for real object-oriented, huh! The OBServer and Observable here respectively correspond to Observer and Subject, compare the methods they define, traces or quite obvious: OBServer: Update (Observable Subject, Object Arg) Monitor Subject, when the Subject object state changes What response will be in Observer, arg is the parameter of the NotifyObservers method passed to OBSERVABLE; OBSERVABLE method:
AddobServer (Observer Observer) Observer Register your own Haschanged () check if the Subject status has changed () Setting the status of this subject to "changed" notifyObservers () Notification Observer This Subject status changes 4. Observer mode in Java The application in the GUI event model is actually used in the AWT / SWING event model. The previous JDK 1.0 AWT uses "Inherited Event Model", which defines a series of event processing methods in the model component class. , Such as: Handleevent, MouseDown, MouseUp, etc. We are implemented by the response of the event is achieved by inheriting and overlying the corresponding event processing method. The component receives the event to the locker, along the container chain until the event Handled by a container's handle method. This model has a lot of disadvantages, and the processing of the event should not be responsible by the event generator, and according to the principle of the "design pattern" book, "inherit" is often considered "destroying the package", the father and son Tightened coupling relationships reduce flexibility while inheriting is easy to cause the scale of family trees, which is not conducive to components. The new event model after JDK 1.1 is "authorized event model", which is the listner model we are familiar with, and the processing of events will no longer be responsible for generating events, but is responsible by listener, only registered. Listener can pass the event action to the component. Especially when designing the MVC structure in the SWING component, it is well known that MVC represents "Model-View-Controller", "Data-Representation Logic - Operation", where data can correspond to a variety of representations, such views The status of Observer, and Model is Subject. JTREE and JTABLE familiar to everyone are this MVC structure: ------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------- Treemodel Jtree TreemodellistenertableModel JTable TablemodelliStener ----------------------- ------------------------------ 5. Simple example returned to the Explorer of this article, we consider doing one Simple picture browser, make the tree selection component and image browsing panel in two different classes, where the picture browsing the panel displays the corresponding picture according to the node of the selected tree, so the picture browsing panel is an Observer, the tree is Subject . Due to Java single inheritance, we can't inherit JPanel and Observable, but you can put a Subject to our class with a combination of objects and triggered the Subject's setchanged method through TreeEctionListener, and notify Observer through the NotifyObservers method. The example code is as follows:
//LeftPanel.javapackage com.jungleford.test; import java.awt.BorderLayout; import javax.swing *;. Import javax.swing.event.TreeSelectionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.tree. DefaultMutableTreeNode; import java.util.Observable; import java.util.Observer; public final class LeftPanel extends JPanel {// select the tree view layout on the left private JTree tree; // select tree view private JScrollPane scroll; // make The view can scroll through the private defaultmutabletreenode root, node1, node2; // root node and two leaf private sensor sensor; // Sensor is an OBSERVABLE, because only single inheritance, so as a combination member private string file; // picture file name , in communication with the content RightPanel public LeftPanel (Observer observer) {file = ""; sensor = new Sensor (); sensor.addObserver (observer); // Register the Observable Observer root = new DefaultMutableTreeNode ( "Images"); tree = new JTree (root); node1 = new DefaultMutableTreeNode ( "Rabbit"); node2 = new DefaultMutableTreeNode ( "Devastator"); root.add (node1); root.add (node2); tree.addTreeSelectionListener (new TreeSelectionListene r () {// tree node selection operation public void valueChanged (TreeSelectionEvent e) {Object obj = e.getPath () getLastPathComponent ();. if (obj instanceof DefaultMutableTreeNode) {DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj; if (node = = root) File = ""; // Select root IF (node == node1) file = "rabbit.jpg"; // Select Node1 if (node == node2) file = "devastator.gif"; // Select Node2 Sensor.SetData (file); // Change OBServable Sensor.notifyObservers (); // Notify Observer, the object has changed}}}); scroll =
new JScrollPane (tree); add (scroll, BorderLayout.CENTER);} public Observable getSensor () {// return Observable objects so Observer can obtain return sensor;}} class Sensor extends Observable {// define their own Observable private Object Data; public void setData (Object newdata) {data = newdata; setChanged (); // change Observable System.Out.println ("Data Changd!");} public object getdata () {return data;}} // RightPanel .javapackage com.jungleford.test; import java.awt *;. import javax.swing.JPanel; import java.util.Observer; import java.util.Observable; public class RightPanel extends JPanel implements Observer {// the picture browser view Layout on the right private image image; public void update (Observable Subject, Object Obj) {// Defines the response action after receiving OBSERVABLE STRING FILE = (STRING) .Getdata (); if (! File); .equals (")) {image = Toolkit.getDefaultToolkit (). getImage (file); MediaTracker Tracker = new Mediatracker (this); // Define Image Track Tracker.AddImage (image, 0); try {tracker.WaitforID (0); // Wait for the full load} catch (interruptedException E) {E.PrintStackTrace ();}} else image = null; repaint (); // redraw component} public void PaintComponent (GRAPHICS G) {g .SETCOLOR (color.light_gray); g.FillRect (0, 0, getWidth () - 1, getHeight () - 1); // Clear IF on the screen on the component (Image! = null) G.DRAWIMAGE , 0, 0, this); // Draw a new image}}
//MainFrame.javapackage com.jungleford.test; import java.awt *;. Import javax.swing.JFrame; public class MainFrame extends JFrame {// presentation window public static void main (String [] args) {MainFrame frame = new MainFrame (); RightPanel right = new RightPanel (); LeftPanel left = new LeftPanel (right); // Register Observer frame.getContentPane () add (left, BorderLayout.WEST);. frame.getContentPane () add (right,. BorderLayout.center; Frame.SetTitle ("Observer Test"); frame.setsize (400, 300); frame.setdefaultcloseOperation (jframe.exit_on_close); Frame.setVisible (TRUE);}} The screenshot is as follows: Start the interface Click Image of Rabbit Click on the image displayed by DEVESTATOR
Appendix: OBServer mode overview
Intecking a one-to-many dependency between the objects, when the status of an object changes, all objects that depend on its object are notified and automatically updated. Motivation Split a system into a series of collaborative classes with a common side effect: need to maintain transplantation between related objects. We do not want to make all kinds of close coupling in order to maintain consistency, as this will reduce their reusability. applicability
When an abstract model has two aspects, one depends on the other, encapsulating the two into independent objects to make them independently change and reuse when changing other objects at the same time, but not I know how much object needs to be changed. When an object must be notified other objects, but it can't assume what other objects are, that is, I don't want these objects to be closely coupled structural diagram participants.
Subject (Observer) CONCRESUBJECT (Specific Objective) ConcreteObserver (Specific Observer) Collaboration Map The effect allows you to change your target and observer. You can reuse the target object alone without having to reuse the observer at the same time, and vice versa. You can also increase the observer to apply the MVC mode related mode without changing the target and other observer.
Mediator Mode Singleton Mode Reference:
Design Patterns: Elements of Reusable Object-Oriented Software, by E. Gamma, R. Helm, R. Johnson, J. Vlissides IBM developerWorks tutorial: Java design patterns 101 Graphic Java 2, Mastering the JFC Volumn I: AWT, by David M GEARY