The Factory Design Pattern

You can safely skip this section on first reading, as it simply describes how and why you use a design pattern with the JAXP library.

If you implement an XML parser in the most straightforward way, code that uses the parser will need implementation-specific knowledge of the parser (such as its classname). That's very undesirable. The whole XML initiative is intended to free your data from single platform lock-ins, so having your code tied to a particular parser undermines the objective. The Java API for XML Processing (JAXP) takes special steps to insulate the API from the specifics of any individual parser.

This makes the parser “pluggable,” meaning you can replace the parsers that come with the library with any other compliant SAX or DOM parser. This is achieved by making sure that you never get a reference to the implementation class directly; you only ever work using an object of the interface type in the JAXP library. It's known as the “Factory” design pattern.

Factories have a simple function: churn out objects. Obviously, a Factory is not needed to make an object. A simple call to a constructor will do it for you. However, the use of Factory allows the library-writer to define an interface for creating an object, but let the Factory decide which exact class to instantiate. The Factory method allows your application classes use a general interface or abstract class, rather than a specific implementation. The interface or abstract class defines the methods that do the work. The implementation fulfills that interface, and is used by the application, but never directly seen by the application.

Figure 27-6 shows an abstract class called “Worker.” Worker has exactly two methods: a() and b(). An interface can equally be used, but let's stick with an abstract class for the example. You also have some concrete classes that extend the abstract class (WorkByJane, WorkByPete, etc.). These are the different implementations that are available to you. They might differ in anything: one is fast but uses a lot of memory, another is slow but uses encryption to secure the data, a third might be able to reach remote resources.

Figure 27-6. Worker abstract class, and subclasses with different methods

image

The idea behind the Factory pattern is that you don't want your application code to know about these implementation classes. You don't want it to be able to invoke the extra methods in the implementation, for example. You want a way to declare and use an instance of one of the implementation classes but have it be typed as the abstract worker class. You further want to do that with your application code seeing as little as possible of the implementation and ideally none.

Figure 27-7 shows the Factory pattern that achieves this:

Figure 27-7. The Factory pattern

image

The factory has a method (usually static, though it doesn't have to be) that will return something that is the type of our abstract class, Worker. Here we have called this routine getWorker. It will actually send back a subtype of Worker, but as you know, if Dog is a subtype of Mammal, wherever a parameter or assignment calls for a Mammal you can give it a Dog. This is not true the other way around, of course, as you cannot supply a general class when a more specific one is called for. The Factory method getWorker will look at the parameters it was sent and decide which kind of Worker implementation is the best one to use: a fast one, a secure one, a small memory one, or whatever. Then it will instantiate one of these subclasses, and return it. Notice that the return type is that of our abstract class, not one of the concrete subtypes.

Our code that calls into the Factory will resemble Figure 27-8.

Figure 27-8. Getting an object from a Factory

image

It gets back a Worker, and the only thing that can be done with a worker is to call a() or b(). There is no opportunity to call any of Pete or Jane's extra methods, shown in Figure 27-6.

You cannot instantiate a Worker object, because it's an abstract class. But by using the Factory pattern, you now hold a concrete object that is of type Worker. Describing how this works with XML parsers will bring some clarity to the Factory pattern.

When using an interface, you don't want to access the underlying implementation classes. If you break this rule, you might as well not be using an interface at all; you have locked yourself into one implementation. In the case of a DOM parser, you want to do everything through the interface, and not directly use the actual DOM parser that implements the interface. The interface is:

package org.w3c.dom;
public interface Document ... { ...

And the concrete class that implements the DOM parser currently looks something like this:

public class PetesPrettyGoodParser implements org.w3c.dom.Document { ...

But we don't want our code to be tied to any one implementation. That means you don't want your code to say:

class MyXMLApp { ...
    Document myDoc = new PetesPrettyGoodParser();    // Avoid this!
         ... = myDoc.petesSpecialMethod();       // Avoid this!

If you did that, you are building knowledge of Pete's Parser into your code and you can accidentally start calling additional methods of Pete's, which violates the intended API. Instead, we want a way to instantiate and access something that is a “PetesPrettyGoodParser,” but without actually naming it. We want to create it and use it totally using interface methods. This is where the Factory Design Pattern comes in. The library code will have a ParserFactory class. The ParserFactory will have a static field or method that will give you a reference to the thing you are trying to keep out of your code. This field or method will typically be called something like getInstance or newInstance. (If the library writer gave it a name of newInstance, don't confuse it with the method of the same name that has a similar purpose in class java.lang.Class.) The Factory method will look like this:

package javax.xml.parsers;
class DocumentBuilderFactory { ...
      static DocumentBuilderFactory newInstance() {
              ...

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.134.17