33.3. Batch Processing

 
[Page 1008 ( continued )]

30.2. MVC

The model-view-controller (MVC) approach is a way of developing components by separating data storage and handling from the visual representation of the data. The component for storing and handling data, known as a model , contains the actual contents of the component. The component for presenting the data, known as a view , handles all essential component behaviors. It is the view that comes to mind when you think of the component. It does all the displaying of the components. The controller is a component that is usually responsible for obtaining data, as shown in Figure 30.1.

Figure 30.1. The controller obtains data and stores it in a model. The view displays the data stored in the model.


Separating a component into a model and a view has two major benefits:

  • It makes multiple views possible so that data can be shared through the same model. For example, a model storing student names can simultaneously be displayed in a combo box and a list box.

  • It simplifies the task of writing complex applications and makes the components scalable and easy to maintain. Changes can be made to the view without affecting the model, and vice versa.

A model contains data, whereas a view makes the data visible. Once a view is associated with a model, it is synchronized with the model. This ensures that all of the model's views display the same data consistently. To achieve consistency and synchronization with its dependent views, the model should notify the views when there is a change in any of its properties that are used in the view. In response to a change notification, the view is responsible for redisplaying the viewing area affected by the property change.

Prior to JDK 1.1, you would create a model by extending the java.util.Observable class, and would create a view by implementing the java.util.Observer interface. Observable and Observer were introduced in JDK 1.0, and their use is not consistent with the JDK 1.1 event model. With the arrival of the new Java event delegation model, using Observable and Observer became obsolete. The JDK event delegation model provides a superior architecture for supporting MVC component development. The model can be implemented as a source with appropriate event and event listener registration methods . The view can be implemented as a listener. Thus, if data is changed in the model, the view will be notified. To enable the selection of the model from the view, simply add the model as a property in the view with a set method.

Let us use an example to demonstrate the development of components using the MVC approach. The example creates a model named CircleModel , a view named CircleView , and a controller named CircleControl . CircleModel stores the properties ( radius , filled , and color ) that describe a circle. filled is a boolean value that indicates whether a circle is filled. CircleView draws a circle according to the properties of the circle. CircleControl enables the user to enter circle properties from a graphical user interface. Create an applet with two buttons named Show Controller and Show View, as shown in Figure 30.2(a). When you click the Show Controller button, the controller is displayed in a frame, as shown in Figure 30.2(b). When you click the Show View button, the view is displayed in a separate frame, as shown in Figure 30.2(c).


[Page 1009]
Figure 30.2. The controller obtains circle properties and stores them in a circle model. The view displays the circle specified by the circle model.

The circle model contains the properties radius , filled , and color , as well as the registration/deregistration methods for the action event, as shown in Figure 30.3.

Figure 30.3. The circle model stores the data and notifies the listeners if the data changes.

When a property value is changed, the listeners are notified. The complete source code for CircleModel is given in Listing 30.1.

Listing 30.1. CircleModel.java
(This item is displayed on pages 1010 - 1011 in the print version)
 1   import   java.awt.event.*; 2   import   java.util.*; 3 4    public class   CircleModel  { 5  /** Property radius. */  6   private double   radius =   20   ; 7 8  /** Property filled. */  9   private boolean   filled; 10 11  /** Property color. */  12   private   java.awt.Color color; 13 14  /** Utility field used by event firing mechanism. */  15   private   ArrayList<ActionListener> actionListenerList; 16 

[Page 1010]
 17   public double   getRadius() { 18   return   radius; 19 } 20 21   public void   setRadius(   double   radius) { 22   this   .radius = radius; 23 24  // Notify the listener for the change on radius  25  processEvent(  26    new   ActionEvent(   this   , ActionEvent.ACTION_PERFORMED,   "radius"   ));  27 } 28 29   public boolean   isFilled() { 30   return   filled; 31 } 32 33   public void   setFilled(   boolean   filled) { 34   this   .filled = filled; 35 36  // Notify the listener for the change on filled  37  processEvent(  38    new   ActionEvent(   this   , ActionEvent.ACTION_PERFORMED,   "filled"   ));  39 } 40 41   public   java.awt.Color getColor() { 42   return   color; 43 } 44 45   public void   setColor(java.awt.Color color) { 46   this   .color = color; 47 48  // Notify the listener for the change on color  49  processEvent(  50    new   ActionEvent(   this   , ActionEvent.ACTION_PERFORMED,   "color"   ));  50 51 } 52 53  /** Register an action event listener */  54   public synchronized void   addActionListener(ActionListener l) { 55   if   (actionListenerList ==   null   ) 56 actionListenerList =   new   ArrayList<ActionListener>(); 57 58 actionListenerList.add(l); 59 } 60 61  /** Remove an action event listener */  62   public synchronized void   removeActionListener(ActionListener l) { 63   if   (actionListenerList !=   null   && actionListenerList.contains(l)) 64 actionListenerList.remove(l); 65 } 66 67  /** Fire TickEvent */  68   private void   processEvent(ActionEvent e) { 69 ArrayList list; 70 71   synchronized   (   this   ) { 72   if   (actionListenerList ==   null   )   return   ; 73 list = (ArrayList)actionListenerList.clone(); 74 } 75 

[Page 1011]
 76   for   (   int   i =     ; i < list. size (); i++) { 77 ActionListener listener = (ActionListener)list.get(i); 78 listener.actionPerformed(e); 79 } 80 } 81 } 

Note

The registration/deregistration/processEvent methods (lines 54 “80) are the same as in Listing 27.2, CourseWithActionEvent.java. If you use a GUI builder tool such as NetBeans, JBuilder, or Eclipse, the code can be generated automatically.


The view implements ActionListener to listen for notifications from the model. It contains the model as its property. When a model is set in the view, the view is registered with the model. The view extends JPanel and overrides the paintComponent method to draw the circle according to the property values specified in the mode. The UML diagram for CircleView is shown in Figure 30.4, and its source code is given in Listing 30.2.

Figure 30.4. The view displays the circle according to the model.

Listing 30.2. CircleView.java
(This item is displayed on pages 1011 - 1012 in the print version)
 1   import   java.awt.*; 2   import   java.awt.event.*; 3 4   public class   CircleView   extends   javax.swing.JPanel 5   implements   ActionListener { 6    private   CircleModel model;  7 8   public void   actionPerformed(ActionEvent actionEvent) { 9 repaint(); 10 } 11 12  /** Set a model */  13   public void   setModel(CircleModel newModel) { 14  model = newModel;  15 16    if   (model !=   null   )  16  // Register the view as listener for the model  18  model.addActionListener(   this   );  19 20 repaint(); 21 } 22 23   public   CircleModel getModel() { 

[Page 1012]
 24   return   model; 25 } 26 27   public void   paintComponent(Graphics g) { 28   super   .paintComponent(g); 29 30    if   (model ==   null   )   return   ;  31 32 g.setColor(model.getColor()); 33 34   int   xCenter = getWidth() /   2   ; 35   int   yCenter = getHeight() /   2   ; 36   int   radius = (   int   )model.getRadius(); 37 38   if   (model.isFilled()) { 39 g.fillOval(xCenter - radius, yCenter - radius, 40   2   * radius,   2   * radius); 41 } 42   else   { 43 g.drawOval(xCenter - radius, yCenter - radius, 44   2   * radius,   2   * radius); 45 } 46 } 47 } 

The controller presents a GUI interface that enables the user to enter circle properties radius , filled , and color . It contains the model as its property. You can use the setModel method to associate a circle model with the controller. It uses a text field to obtain a new radius and a combo box to obtain a Boolean value to specify whether the circle is filled. The source code for CircleController is given in Listing 30.3.

Listing 30.3. CircleController.java
(This item is displayed on pages 1012 - 1013 in the print version)
 1   import   java.awt.event.*; 2   import   java.awt.*; 3   import   javax.swing.*; 4 5   public class   CircleController   extends   JPanel { 6    private   CircleModel model;  7   private   JTextField jtfRadius =   new   JTextField(); 8   private   JComboBox jcboFilled =   new   JComboBox(   new   Boolean[]{ 9   new   Boolean(   false   ),   new   Boolean(   true   )}); 10 11  /** Creates new form CircleController */  12   public   CircleController() { 13  // Panel to group labels  14 JPanel panel1 =   new   JPanel(); 15 panel1.setLayout(   new   GridLayout(   2   ,   1   )); 16 panel1.add(   new   JLabel(   "Radius"   )); 17 panel1.add(   new   JLabel(   "Filled"   )); 18 19  // Panel to group text field, combo box, and another panel  20 JPanel panel2 =   new   JPanel(); 21 panel2.setLayout(   new   GridLayout(   2   ,   1   )); 22 panel2.add(jtfRadius); 23 panel2.add(jcboFilled); 24 25 setLayout(   new   BorderLayout()); 26 add(panel1, BorderLayout.WEST); 27 add(panel2, BorderLayout.CENTER); 

[Page 1013]
 28 29  // Register listeners  30  jtfRadius.addActionListener(   new   ActionListener() {  31   public void   actionPerformed(ActionEvent e) { 32    if   (model ==   null   )   return   ;   // No model associated yet. Do nothing  33  model.setRadius(   new   Double(jtfRadius.getText()).doubleValue());  34 } 35 }); 36  jcboFilled.addActionListener(   new   ActionListener() {  37   public void   actionPerformed(ActionEvent e) { 38    if   (model ==   null   )   return   ;   // No model associated yet. Do nothing  39  model.setFilled(  40  ((Boolean)jcboFilled.getSelectedItem()).booleanValue());  41 } 42 }); 43 } 44 45   public void   setModel(CircleModel newModel) { 46 model = newModel; 47 } 48 49   public   CircleModel getModel() { 50   return   model; 51 } 52 } 

Finally, let us create an applet named MVCDemo with two buttons, Show Controller and Show View . The Show Controller button displays a controller in a frame, and the Show View button displays a view in a separate frame. The program is shown in Listing 30.4.

Listing 30.4. MVCDemo.java
(This item is displayed on pages 1013 - 1014 in the print version)
 1   import   java.awt.*; 2   import   java.awt.event.*; 3   import   javax.swing.*; 4 5   public class   MVCDemo   extends   JApplet { 6   private   JButton jbtController =   new   JButton(   "Show Controller"   ); 7   private   JButton jbtView =   new   JButton(   "Show View"   ); 8    private   CircleModel model =   new   CircleModel();  9 10   public   MVCDemo() { 11 setLayout(   new   FlowLayout()); 12 add(jbtController); 13 add(jbtView); 14 15 jbtController.addActionListener(   new   ActionListener() { 16   public void   actionPerformed(ActionEvent e) { 17 JFrame frame =   new   JFrame(   "Controller"   ); 18 CircleController controller =   new   CircleController(); 19 controller.setModel(model); 20 frame.add(controller); 21 frame.setSize(   200   ,   200   ); 22 frame.setLocation(   200   ,   200   ); 23 frame.setVisible(   true   ); 24 } 25 }); 26 27 jbtView.addActionListener(   new   ActionListener() { 28   public void   actionPerformed(ActionEvent e) { 

[Page 1014]
 29 JFrame frame =   new   JFrame(   "View"   ); 30 CircleView view =   new   CircleView(); 31 view.setModel(model); 32 frame.add(view); 33 frame.setSize(   500   ,   200   ); 34 frame.setLocation(   200   ,   200   ); 35 frame.setVisible(   true   ); 36 } 37 }); 38 } 39 } 

The model stores and handles data, and the views are responsible for presenting data. The fundamental issue in the model-view approach is to ensure consistency between the views and the model. Any change in the model should be notified to the dependent views, and all the views should display the same data consistently. The data in the model is changed through the controller.

The methods setRadius and setFilled , and setColor (lines 21, 33, 45) in CircleModel invoke the processEvent method to notify the listeners of any change in the properties. The setModel method in CircleView sets a new model and registers the view with the model by invoking the model's addActionListener method (line 18). When the data in the model is changed, the view's actionPerformed method is invoked to repaint the circle (line 9).

The controller CircleController presents a GUI. You can enter the radius from the radius text field. You can specify whether the circle is filled from the combo box that contains two Boolean objects, new Boolean(false) and new Boolean(true) (lines 8 “9). Several controllers or views can share a model. Every time you click the Show Controller button, a new controller is created (line 18). Every time you click the Show View button, a new view is created (line 30). All the controllers and views share the same model.

 


Introduction to Java Programming-Comprehensive Version
Introduction to Java Programming-Comprehensive Version (6th Edition)
ISBN: B000ONFLUM
EAN: N/A
Year: 2004
Pages: 503

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net