![]() |
|||
![]() ![]() |
![]() |
![]()
|
![]() |
It should be pointed out that the JFC contains convenience methods for handling simple examples such as that shown previously. The most likely manner in which this example would be coded using the JFC is as follows: String[] fruits = { "Apple", "Banana", "Orange", "Pear" }; JList list = new JList( fruits ); In this example, the JList class creates an anonymous inner class that implements the ListModel interface. This model, which is hidden from the caller, wraps the array given in the JList constructor. The inner class is used by the list component as the data model. The previous discussion illustrates the power of the JFC toolkit. It can be used as a lightweight viewing engine for any data source, or, using default models and convenience methods, it can be used like a traditional widget toolkit. Most production applications will exhibit examples of both uses of the JFC toolkit. The JFC provides the Action interface to embody elements of application behavior. The JFC provides many Action-aware components that allow an action to be easily tied to a keystroke, menu item, or toolbar. If an application or applet is developed with actions that define behavior, the actions may be thought of as the controllers in the MVC architecture. The Action interface will be presented in detail in Chapter 4, JFC Programming Techniques, and examples of Action-aware components will be presented throughout this book. Factory Design PatternThe version of the MVC design pattern implemented in the JFC may be the most visible pattern used, but there are others sprinkled throughout. The parameterized factory design pattern creates an instance of a class depending on the parameter given to the factory. This pattern is easily implemented in Java and is used to hide specific class details from a Client class. The parameterized factory pattern can be implemented in Java by exposing an interface that defines the behavior of classes in a package. Then one or more static creation functions are provided for clients to obtain instances of classes in the package. Parameters passed to one of the construction methods determine which class in the package is instantiated. The Client class interacts with the Concrete class returned from the factory creation method through the public methods defined in the packages public interface(s). Parameterized Factory Pattern ExampleThe following example demonstrates the parameterized factory design pattern. The example implements a Reporter package that writes messages to either the console or a file. An application uses a factory method to obtain a reference to a Reporter. The client code interacts with the Reporter through the methods defined in the Reporter interface shown here. package com.foley.reporter; import java.io.IOException; /** * The Reporter interface. All types of * Reporters must implement this interface. A client * gets a handle to a Reporter using the ReporterFactory * class. * * @see ReporterFactory * @author Mike Foley **/ public interface Reporter { /** * Method to write a message to the reporting system. * A newline is added after the message is written. * * @param message The message to be written. **/ public void writeln( String message ) throws IOException; /** * Existing Reporter types. **/ static final ReporterType CONSOLE = new ReporterType(); static final ReporterType FILE = new ReporterType(); /** * Type safe class for reporters. **/ final class ReporterType { } } // Reporter In this simple example, the Reporter only defines one method, writeln. Also of interest in the Reporter interface are the type-safe constants of defined Reporter types. These types are used in the ReporterFactory as well as by clients to specify the type of Reporter desired. The ReporterFactory, shown next, is used by clients to obtain a handle on a Reporter of the desired type. The static getReporter method is passed one of the type-safe constants defined in the Reporter interface. This value is tested, and the proper Reporter type is returned to the caller. Using the type-safe constants in the getReporter method allows the compiler to detect improper type requests. This would not be possible if an int was used for the Reporter type. The ReporterFactory lazily creates a single Reporter instance of the proper type when it is requested. Clients requesting the Reporter share the single instance of the requested type. However, this implementation detail is hidden from the client. If a separate FileReporter is desired for each client, this change may be implemented in the factory without altering client code. package com.foley.reporter; import java.io.IOException; /** * A factory class to retrieve a Reporter of the specified * type. If additional Reporter types are added to the system, * the factory method must be updated to construct the new types. * * @author Mike Foley **/ public class ReporterFactory extends Object { /** * The shared Reporter instances. * These are lazily created when requested. **/ private static ConsoleReporter consoleReporter; private static FileReporter fileReporter; /** * Method to obtain a Reporter. * * @param type The type of Reporter desired. * @return The Reporter of the specified type. * @exception IOException If the Reporter can not be initialized. **/ public static Reporter getReporter( Reporter.ReporterType type ) throws IOException { if( type == Reporter.CONSOLE ) { // // Return the console reporter instance. // If this doesn't yet exist, create it. // if( consoleReporter == null ) consoleReporter = new ConsoleReporter(); return( consoleReporter ); } else if( type == Reporter.FILE ) { // // Return the file reporter instance. // If this doesnt yet exist, create it. // if( fileReporter == null ) fileReporter = new FileReporter(); return( fileReporter ); } throw( new RuntimeException( "A new Reporter type must have been added." ) ); } // getReporter } // ReporterFactory
|
![]() |
|