JMU
Design Patterns
An Introduction for Beginning Programmers


Prof. David Bernstein
James Madison University

Computer Science Department


Software Design Patterns
Software Design Patterns (cont.)
The Purpose(s) of this Presentation
Singleton Pattern - Motivation
Singleton Pattern - The Traditional Approach

images/singleton.gif

Singleton Pattern - An Example
A FileViewer
javaexamples/singleton/v1/FileViewer.java (Fragment: skeleton)
        

/**
 * A Frame that is used to view the contents of a file
 *
 * This class  uses the Singleton pattern 
 * to ensure that there is only one
 * instance at any point in time.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 *
 */
public class FileViewer
{

    private static boolean      exists = false;
    private static FileViewer   instance;

    /**
     * Construct a new FileViewer
     *
     * Note: This method is private and used only internally
     */
    private FileViewer()
    {


        exists = true;
    }

}

        
javaexamples/singleton/v1/FileViewer.java (Fragment: createInstance)
        
    /**
     * Construct a new FileViewer (if one doesn't exist)
     * or return the existing instance
     */
    public static FileViewer createInstance()
    {
       if (!exists) instance = new FileViewer(); // exists will become true
       
       return instance;

    }
        
Singleton Pattern - An Example (cont.)
Using a FileViewer
javaexamples/singleton/v1/FileChooser.java (Fragment: valueChanged)
        
    /**
     * Handle valueChanged events 
     * (required by ListSelectionListener)
     *
     * @param lse   The ListSelectionEvent to handle
     */
    public void valueChanged(ListSelectionEvent lse)
    {
        FileViewer   fv;
        String       fn;

        fn = (String)list.getSelectedValue();

        fv = FileViewer.createInstance();
        fv.load(fn);
    }
        
Iterator - Motivation
Iterator - Motivation (cont.)

Looping Over an Array

javaexamples/iterator/ArrayExample.java (Fragment: 1)
        
       String    city;

       for (int i=0; i < cities.length; i++)
       {
          city = cities[i];
          System.out.println(city);
       }
        

Looping Over a Vector

javaexamples/iterator/VectorExample.java (Fragment: 1)
        
       String    city;

       for (int i=0; i < cities.size(); i++)
       {
          city = (String)cities.elementAt(i);
          System.out.println(city);
       }
        
Iterator - The Traditional Approach

In UML:

images/iterator.gif
Iterator - Examples in Java
Model-View-Controller - Motivation
M-V-C - The Traditional Approach
images/mvc_pattern.gif
M-V-C - An Example
images/MVCTextField_context.gif
M-V-C - An Example: (cont.)

Handling an arrowkeyPressed Event

images/MVCTextField_arrowkeyPressed.gif
M-V-C - An Example: (cont.)

Handling a mouseUp Event

images/MVCTextField_mouseUp.gif
M-V-C - An Example: (cont.)

Handling a characterKeyPressed Event

images/MVCTextField_characterkeyPressed.gif
M-V-C - Concrete Examples

Creating an Integer Entry Field

javaexamples/mvc/IntegerDocument.java
        package mvc;

import javax.swing.text.*;

/**
 * A Document that can only contain integer values
 *
 * Note: In order to be simple and clear, this implementation
 * does not support numbers with a leading '+' and will not allow
 * the document to contain only a '-'.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class IntegerDocument extends PlainDocument
{

    /**
     * Check to see if an insertString() will result in an Integer or
     * not.
     *
     * @param  offset  The starting offset
     * @param  text    The string to insert
     * @return         true if OK; false otherwise
     */
    public boolean checkInsert(int offset, String text)
    {
       boolean      result;       
       String       newText;
       
       try 
       {
          newText = super.getText(0, offset) + text + 
             super.getText(offset, getLength()-offset);

          Integer.parseInt(newText);
          result = true;
       }
       catch (Exception e)
       {
          result = false;
       }

       return result;       
    }

    /**
     * Check to see if a remove() will result in an Integer or not.
     *
     * @param  offset  The starting offset
     * @param  length  The length to remove
     * @return         true if OK; false otherwise
     */
    public boolean checkRemove(int offset, int remove)
    {
       boolean      result;       
       String       newText;
       
       try 
       {
          newText = super.getText(0, offset) + 
             super.getText(offset+remove, getLength()-offset-remove);

          if (!newText.equals("")) Integer.parseInt(newText);
          result = true;
       }
       catch (Exception e)
       {
          result = false;
       }

       return result;       
    }
    

    /**
     * Check to see if a replace() will result in an Integer or
     * not.
     *
     * @param  offset  The starting offset
     * @param  length  The length to remove
     * @param  text    The string to insert
     * @return         true if OK; false otherwise
     */
    public boolean checkReplace(int offset, int remove, String text)
    {
       boolean      result;       
       String       newText;
       
       try 
       {
          newText = super.getText(0, offset) + text + 
             super.getText(offset+remove, getLength()-offset-remove);

          if (!newText.equals("")) Integer.parseInt(newText);
          result = true;
       }
       catch (Exception e)
       {
          result = false;
       }

       return result;       
    }
    

    /**
     * Inserts content into the document (but only if 
     * the result is an Integer)
     *
     * @param offset   The starting offset
     * @param text     The string to insert
     * @param a        The attributes for the inserted text
     */
    public void insertString(int offset, String text, AttributeSet a) 
                throws BadLocationException
    {
       if (checkInsert(offset, text)) super.insertString(offset, text, a);
    }

    /*
     * Remove some content from the document (but only if the result is
     * a SimpleTime).
     *
     * @param offset The starting offset
     * @param length The number of characters to remove 
     */
    public void remove(int offset, int length) 
                throws BadLocationException
    {
       if (checkRemove(offset, length)) super.remove(offset, length);
    }


    /**
     * Deletes the region of text from offset to offset + length, and
     * replaces it with text.
     *
     * @param offset The starting offset
     * @param length The number of characters to remove 
     * @param text   The string to insert
     * @param a      The attributes for the inserted text
     */
    public void replace(int offset, int length, String text, AttributeSet a)  
                throws BadLocationException
    {
       if (checkReplace(offset, length, text)) 
          super.replace(offset, length, text, a);
    }
}
        
javaexamples/mvc/IntegerEntryField.java
        package mvc;

import javax.swing.*;
import javax.swing.text.*;

/**
 * An entry field that only accepts integers
 *
 * Note: In order to be simple and clear, this implementation
 * does not support numbers with a leading '+' and will not allow
 * the document to contain only a '-'.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0 
 */
public class IntegerEntryField extends JTextField
{
    /**
     * Create a Document (i.e., model) for this IntegerEntryField
     *
     * @return  An IntegerDocument
     */
    protected Document createDefaultModel()
    {
        return new IntegerDocument();
    }
}
        

Creating a Password Entry Field

What would you change and why?

Skins

What would you change and why?

Other Software Design Patterns
Decorator - Motivation
Decorator - The Traditional Approach
images/decorator_pattern.gif
Decorator - A Generic Application
images/decorator_pattern_sequence-diagram.gif
Decorator - An Example
images/decorator_pattern_printer-example.gif
Decorator - An Example (cont.)
javaexamples/decorator/Printer.java
        /**
 * The requirements of a Printer
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public interface Printer
{
    /**
     * Print the given String
     *
     * @param text   The String to print
     */
    public abstract void print(String text);    
}

        
javaexamples/decorator/ConsolePrinter.java
        /**
 * Prints text to the console
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class ConsolePrinter implements Printer
{
    /**
     * Print the given String
     *
     * @param text   The String to print
     */
    public void print(String text)
    {
       System.out.print(text);       
    }
    

}
        
javaexamples/decorator/PrinterDecorator.java
        /**
 * An abstract decorator of Printer
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public abstract class PrinterDecorator implements Printer
{
    protected Printer     decorated;
    
    /**
     * Explicit Value Constructor
     *
     * @param decorated    The Printer to decorate
     */
    public PrinterDecorator(Printer decorated)
    {
       this.decorated = decorated;       
    }
    

    /**
     * Print the given String
     * (required by Printer)
     *
     * @param text   The String to print
     */
    public void print(String text)
    {
        decorated.print(text);
    }
}
        
javaexamples/decorator/UppercasePrinter.java
        /**
 * A Printer that always prints in uppercase
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class UppercasePrinter extends PrinterDecorator
{
    /**
     * Explicit Value Constructor
     *
     * @param decorated    The Printer to decorate
     */
    public UppercasePrinter(Printer decorated)
    {
       super(decorated);       
    }
    

    /**
     * Print the given String
     * (required by Printer)
     *
     * @param text   The String to print
     */
    public void print(String text)
    {
       decorated.print(text.toUpperCase());       
    }
}

        
javaexamples/decorator/WrappingPrinter.java
        import java.util.*;

/**
 * A Printer that wraps at word boundaries
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class WrappingPrinter extends PrinterDecorator
{
    protected int         width;
    

    /**
     * Explicit Value Constructor
     *
     * @param decorated    The Printer to decorate
     * @param width        The maximum width
     */
    public WrappingPrinter(Printer decorated, int width)
    {
       super(decorated);       
       this.width = width;       
    }
    

    /**
     * Print the given String
     * (required by Printer)
     *
     * @param text   The String to print
     */
    public void print(String text)
    {
       int                    required, used;       
       String                 token;       
       StringTokenizer        st;
       
       st   = new StringTokenizer(text);
       used = 0;       

       while (st.hasMoreTokens())
       {
          token    = st.nextToken();
          required = token.length();
          
          if ((required + used + 1) > width)
          {
             decorated.print("\n");
             decorated.print(token);             
             used = required + 1;
          }
          else
          {
             if (used != 0) 
             {
                decorated.print(" ");
                ++used;
             }
             
             decorated.print(token);
             used += required;             
          }
       }
    }
}

        
javaexamples/decorator/Driver.java
        /**
 * An application that demonstrates the use of the
 * Decorator Pattern
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class Driver
{
    /**
     * The entry point
     *
     * @param args   The command line arguments
     */
    public static void main(String[] args)
    {
       Printer           printer;       
       String            text;
       

       text = "This is the text that we will use " +
              "to demonstrate the capabilities "   +
              "of different Printer objects.";
       

       printer = new ConsolePrinter();
       printer.print(text);       

       System.out.print("\n\n");       

       printer = new UppercasePrinter(new ConsolePrinter());
       printer.print(text);       

       System.out.print("\n\n");       

       printer = new WrappingPrinter(new ConsolePrinter(), 20);
       printer.print(text);       

       System.out.print("\n\n");       

       printer = new WrappingPrinter(
                     new UppercasePrinter(
                         new ConsolePrinter()), 20);
       printer.print(text);       
    }
    
}