Tuesday, October 27, 2009

Template Method




















Chapter 8 -
Behavioral Patterns
Patterns in Java, Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML, Second Edition
by Mark Grand
John Wiley & Sons � 2002



























Template Method



This pattern was previously described in [GoF95].




Synopsis


Write an abstract class that contains only part of the logic needed to accomplish its purpose. Organize the class so that its concrete methods call an abstract method where the missing logic would have appeared. Provide the missing logic in the subclass’s methods that override the abstract methods.






Context


Suppose that you have the task of writing a reusable class for logging users into an application or applet. In addition to being reusable and easy to use, the tasks of the class will be to:




















l



Prompt the user for a user ID and password.




l



Authenticate the user ID and password. The result of the authentication operation should be an object. If the authentication operation produces some information needed later as proof of authentication, then the object produced by the authentication operation should encapsulate the information.




l



While the authentication operation is in progress, the user should see a changing and possibly animated display that tells the user that authentication is in progress and all is well.




l



Notify the rest of the application or applet that login is complete and make the object produced by the authentication operation available to the rest of the application.




Two of these tasks¾prompting the user and assuring the user that authentication is in progress¾are application independent. Though the strings and images displayed to the user may vary with the application, the underlying logic will always be the same.


The other two tasks¾authenticating the user and notifying the rest of the application¾are application specific. Every application or applet will have to provide its own logic for these tasks.


The way that you organize your Logon class will be a large factor in how easy it is for developers to use. Delegation is a very flexible mechanism. You could simply organize a Logon class so that it delegates the tasks of authenticating the user and notifying the rest of the application. Though this approach gives a programmer a lot of freedom, it does not help guide a programmer to a correct solution.


Programmers are unlikely to make frequent use of your Logon class. This means that when they use it, they will probably not be very familiar with it. Just as it can be easier to fill in the blanks of a preprinted form than to write a document from scratch, giving your Logon class a fill-in-the-blanks organization can guide programmers to the correct use of the Logon class. You can achieve a fill-in-the-blanks organization by defining the Logon class to be an abstract class that defines abstract methods that correspond to the application-dependent tasks that the programmer must supply code for. To use the Logon class, a programmer must define a subclass of the Logon class. Because the methods corresponding to the tasks that the programmer must code are abstract methods, a Java compiler will complain if the programmer does not fill in the blanks by overriding the abstract methods.



Figure 8.29 presents a diagram that shows the organization of a Logon class organized in that way and its subclass.






Figure 8.29: Logon class and subclass.

The AbstractLogon class has a method called logon that contains the top-level logic for the top-level task of logging a user on to a program. It calls the abstract methods authenticate and notifyAuthentication to perform the program-specific tasks of authenticating a user and notifying the rest of the program when the authentication is accomplished.






Forces























J



You have to design a class for reuse in multiple programs.




J



The overall responsibility of the class will be the same for all applications. However, portions of its behavior will be different in each program in which it is used.




J



You can make the class easier for programmers unfamiliar with the class to use by designing it in a way that reminds programmers who use the class to supply logic for all its program-specific responsibilities.




J



If a Java class that is not abstract inherits an abstract method but does not override it, then Java compilers will complain when compiling it.




L



Designing a class to remind programmers to supply logic for its program-specific responsibilities requires additional effort. If the class is not reused, then the additional effort is wasted.








Solution


Organize reusable logic into an abstract class that calls application-specific logic through place markers in the form of abstract methods. To use the abstract class, the programmer must create a subclass that overrides the abstract methods with application-specific logic.



Figure 8.30 is a class diagram that shows the organization of the Template Method pattern.






Figure 8.30: Template Method pattern.

Following are descriptions of the roles played by classes in the Template Method pattern:



AbstractTemplate.  A class in this role has a concrete method that contains the class’s top-level logic. The method is indicated in the diagram as templateMethod. This method calls other methods, defined in the AbstractTemplate class as abstract methods, to invoke lower-level logic that varies with each subclass of the AbstractTemplate class.



ConcreteTemplate.  A class in this role is a concrete subclass of an AbstractTemplate class. It overrides the abstract methods defined by its superclass to provide the logic needed to complete the logic of the templateMethod method.






Implementation


The basic way an AbstractTemplate class provides guidance to a programmer is by forcing him or her to override abstract methods with the intention of providing logic to fill in the blanks of its template method’s logic. You can add more structure by providing additional methods for subclasses to override with supplemental or optional logic. For example, consider a reusable class called Paragraph that represents paragraphs in a word processor document.


One of the Paragraph class’s responsibilities is to determine how to wrap the words it contains into lines that fit within specified margins. The Paragraph class has a template method responsible for wrapping the words in a paragraph. Because some word processors allow paragraphs to wrap around graphics, the Paragraph class defines an abstract method that the class’s word-wrapping logic calls to determine the margins for a line of text. Concrete subclasses of the paragraph class are forced to provide an implementation of that method to determine the margins for each line.


Some word processors include a hyphenation engine that automatically determines where words can be hyphenated. This feature allows longer words to be split between lines so the lines of a paragraph can be of more even lengths. Since not every word processor will require the Paragraph class to support hyphenation, it does not make sense for the Paragraph class to define an abstract hyphenation method and force subclasses to override it. However, it is helpful for the Paragraph class to define a concrete hyphenation method that is called by the word-wrapping logic and does nothing. The point of such a method is that a subclass of Paragraph can override the method in those cases where hyphenation needs to be supported.


Methods such as those that can be optionally overridden to provide additional or customized functionality are called hook methods. To make it easier for a programmer to be aware of the hook methods that a class provides, you can apply a naming convention to hook methods. Two of the more common naming conventions for hook methods are to either begin the names of hook methods with the prefix do- or end the names of hook methods with the suffix -Hook. For example, following those naming conventions, the name of the Paragraph class’s hyphenation method might be doHyphenation or hyphenationHook.






Consequences


A programmer writing a subclass of an AbstractTemplate class is forced to override those methods that must be overridden to complete the logic of the superclass. A well-designed template method class has a structure that provides a programmer with guidance in providing the basic structure of its subclasses.






Code Example


Following is some code that implements the design presented under the Context heading. First is the AbstractLogon class. It participates in the Template Method pattern in the AbstractTemplate role. Its template method is called logon. The logon method puts up a dialog that prompts the user for a user ID and password. After the user supplies a user ID and password, the logon method pops up a window telling the user that authentication is in progress. The window stays up while the logon method calls the abstract method authenticate to authenticate the user id and password. If the authentication is successful, it takes down the dialog boxes and calls the abstract method notifyAuthentication to notify the rest of the program that the user has been authenticated.




public abstract class AbstractLogon {
/**
* This method authenticates a user.
* @param frame
* The parent frame of dialogs this method pops up.
* @param programName The name of the program
*/
public void logon(Frame frame, String programName) {
        Object authenticationToken;
        LogonDialog logonDialog;
        logonDialog = new LogonDialog(frame,
                                     "Log on to "+programName);
        JDialog waitDialog = createWaitDialog(frame);


The LogonDialog class implements a dialog to prompt the user for logon information. The waitDialog variable refers to a window containing a message for the user that authentication is in progress.




        while(true) {
            waitDialog.setVisible(false);
            logonDialog.setVisible(true);
            waitDialog.setVisible(true);
            try {
                String userID = logonDialog.getUserID();
                String password = logonDialog.getPassword();
                authenticationToken = authenticate(userID,
                                                   password);
                break;
            } catch (Exception e) {
// Tell user that Authentication failed
                JOptionPane.showMessageDialog(frame,
                                              e.getMessage(),
"Authentication Failure",
                                   JOptionPane.ERROR_MESSAGE);
            }  // try
       }
// Authentication successful
        waitDialog.setVisible(false);
        logonDialog.setVisible(false);
        notifyAuthentication(authenticationToken);
    } // logon()
...


The remainder of this listing simply shows the abstract methods the AbstractLogon class defines that the logon method calls.



    /**
* Authenticate user based on the supplied user id and
* password.
* @param userID the supplied user id
* @param password the supplied password
* @return object encapsulating proof of authentication.
*/
    abstract protected Object authenticate(String userID,
                                           String password)
                       throws Exception;

/**
* Notify the rest of program that user is authenticated.
* @param authToken
* What the authenticate method returned.
*/
    abstract
    protected void notifyAuthentication(Object authToken) ;
} // class AbstractLogon


Subclasses of the AbstractLogon class must override its abstract methods like this:



public class Logon extends AbstractLogon {
...
    protected Object authenticate(String userID,
                                  String password)
                     throws Exception {
        if (userID.equals("abc") && password.equals("123"))
          return userID;
        throw new Exception("bad userID");
    } // authenticate

    protected void notifyAuthentication(Object authToken) {
...
    } // notify(Object)
} // class Logon





Related Patterns



Strategy.  The Strategy pattern modifies the logic of individual objects at runtime. The Template Method pattern modifies the logic of an entire class at compile time.


















No comments:

Post a Comment