10.9 Defining the Java Event Model by Extending a Vector

 < Day Day Up > 



10.9 Defining the Java Event Model by Extending a Vector

The Java Event Model used in the animator in Chapter 7 (and defined in the Sun Java Beans Spec [SUN96]) used a utility class to store the listeners, a Vector. This was done using by including the vector of listeners as a variable in the animator class; hence, the reuse was achieved using composition. It could be argued, however, that the animator is a case where the use of classification would have worked better. For example, the addDrawListener and removeDrawListener methods do nothing except delegate the responsibility for adding and removing the listener by calling the method in the vector. If the animator had extended class Vector, then the addElement and removeElement methods could be called directly, and these routines would not have had to be written, saving the programmer the necessity of writing these two methods.

This argument has two problems. The first is that the animator already extends a JPanel, giving it the ability to be placed on a frame. This uses up the single inheritance allowed by Java, which shows why it is important to consider what an object inherits from in Java. Second, while it is obviously true that extending class Vector would save the programmer a very small amount of time writing add and remove methods, the more important question is which design is safer and more extensible. These are the qualities that make the program more useful. The animator developed with composition in Chapter 7 offers four advantages compared to the classification method, all of which are much more important than the savings incurred by not having to implement the addDrawListener and removeDrawListener methods:

  1. In Java, only single inheritance is allowed, and because the animator already extends JPanel it is impossible to create the animator by extending class Vector. This is generally true of classification in Java. Because Java allows only single inheritance, the programmer needs to decide carefully what one class should be extended.

  2. The purpose of the objects in the vector is to store objects that are DrawListeners, as they will eventually be cast to a DrawListener and have their draw methods called. By creating an addDrawListener method that takes only DrawListeners as parameters, it is guaranteed that only objects of type DrawListener will ever be stored in the vector. If a programmer attempts to add anything that is not a DrawListener then an error will be produced at compile time; however, if the addElement method of the vector is used directly it is possible for objects that are not DrawListeners to be added to the vector. This will cause a runtime ClassCastException when an attempt is made to cast the object to a DrawListener to call the draw method. It is a generally accepted principle that it is always best to catch a problem as early as possible in the software development process, when it is easier and less expensive to fix. Even if only one situation ever occurs where software is released and some set of logic allows a non DrawListener object to be added to the animator's vector, the cost of fixing that bug and reissuing the software (not to mention the ill will that is caused) will be many orders of magnitude greater than the cost involved in writing the addDrawListener and removeDrawListener methods.

  3. The animator has not made any external promises to the programs that use it as to how the listeners are stored, so it can change the class that is used to define the container for the listeners without any impact on the programs that use it. This was important in the case of the Java Event Model. The Java Event Model originally defined listeners as being stored in vector classes, and the vector was cloned when processing the event; however, because the listeners vector is cloned when the events are processed, but the add and remove methods are called less frequently, it is better to clone this vector as part of the add and remove method, rather than when the events are processed. EventMulticaster classes, such as the DrawEventMulticaster class used in Program 7.6, were created and the Java AWT was changed to use these EventMulticasters. Because the class used to store the listeners is private, this type of change can be made without affecting the programs that used the AWT classes.

  4. We might not want all of the functionality of the Vector class to be available for manipulating the listener's vector. The vector in the animator is not as good an example as the classic mistake made when implementing the Stack class in the java.util package. A stack needs to store elements in a collection, so the Stack class in Java was implemented to extend the Vector class. This made all the methods of the Vector class accessible to stack objects, so programs could misuse the stack by doing things like adding objects at places other than the top of the stack. This poor behavior is shown in Exhibit 10 (Program10.7), where an object is added at the bottom of the stack.

    Exhibit 10: Program10.7: Improper Use of Stack Object

    start example

     import java.util.Stack; public class UseStack {   public static void main(String args[]) {     try {       Stack stack = new Stack();       stack.push("Element 1");     // The next statement is invalid for a stack.       stack.add(1, "Element 2");     // Note that the items in the stack are in the wrong order       System.out.println(stack.pop());       System.out.println(stack.pop());     } catch(Exception e) {      e.printStackTrace();     }   } } 

    end example

Sections 10.8 and 10.9 provided a number of reasons why using classification to extend what is basically a utility class results in poor designs; however, problems like these often are apparent only after the program has been implemented. What is needed is some way to evaluate a design using basic principles that would predict whether or not a design is likely to result in problems such as those in Sections 10.8 and 10.9. The principles we will use are cohesion and coupling.



 < Day Day Up > 



Creating Components. Object Oriented, Concurrent, and Distributed Computing in Java
The .NET Developers Guide to Directory Services Programming
ISBN: 849314992
EAN: 2147483647
Year: 2003
Pages: 162

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