JMU
Designing with Constructors and Factories
An Introduction with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Review of Constructors
Design Issues
Review of an Earlier Example
Review of an Earlier Example (cont.)
javaexamples/oopbasics/finance/SecurityQuotation.java
import java.util.Calendar;
import java.util.GregorianCalendar;


/**
 * An abstract SecurityQuotation (extended by StockQuotation, 
 * FutureQuotation, etc...).
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public abstract class SecurityQuotation
{
    protected GregorianCalendar   date;
    protected double              open, high, low, close;
    protected int                 volume;
    

    /**
     * Explicit Value Constructor.
     *
     * @param date      The date of the entry
     * @param open      The opening price
     * @param high      The high price
     * @param low       The low price
     * @param close     The closing price
     * @param volume    The volume traded
     */
    protected SecurityQuotation(GregorianCalendar date, 
                                double open,double high,double low,double close,
                                int volume)
    {
       this.date = date;
       this.open = open;
       this.high = high;
       this.low = low;
       this.close = close;
       this.volume = volume;
    }
    
    /**
     * Return the closing price.
     *
     * @return    The closing price
     */
    public double getClose()
    {
       return close;
    }

    /**
     * Return the date.
     *
     * @return    The date of this quotation
     */
    public GregorianCalendar getDate()
    {
       return date;
    }

    /**
     * Return the high price.
     *
     * @return    The high price
     */
    public double getHigh()
    {
       return high;
    }

    /**
     * Return the low price
     *
     * @return    The low price
     */
    public double getLow()
    {
       return low;
    }

    /**
     * Return the opening price.
     *
     * @return    The opening price
     */
    public double getOpen()
    {
       return open;
    }

    /**
     * Return the ticker symbol.
     */
    public abstract String getSymbol();
        

    /**
     * Returns the volume.
     *
     * @return    The volume
     */
    public int getVolume()
    {
       return volume;
    }

    /**
     * Return a String representation.
     *
     * @return   The String representation
     */
    public String toString()
    {
        return getSymbol() + "\t" +
            (date.get(Calendar.MONTH)+ 1) + "/" +
            date.get(Calendar.DAY_OF_MONTH) + "/" +
            date.get(Calendar.YEAR) +
            "\tO: " + open + "\tH: " + high +
            "\tL: " + low + "\tC: " + close + 
            "\tV: " + volume;
    }
}
        
Review of an Earlier Example (cont.)
javaexamples/oopbasics/finance/StockQuotation.java
import java.util.GregorianCalendar;


/**
 * A stock quotation (i.e., open, high, low, close and  volume).
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class StockQuotation extends SecurityQuotation
{
    protected String           symbol;


    /**
     * Explicit Value Constructor.
     *
     * @param symbol    The ticker symbol of the stock
     * @param date      The date of the entry
     * @param open      The opening price
     * @param high      The high price
     * @param low       The low price
     * @param close     The closing price
     * @param volume    The volume traded
     */
    public StockQuotation(String symbol, GregorianCalendar date, 
                          double open,double high,double low,double close,
                          int volume)
    {
        super(date, open, high, low, close, volume);
        this.symbol = symbol;
    }

    /**
     * Return the ticker symbol (required by SecurityQuotation).
     *
     * @param symbol     The ticker symbol
     */
    public String getSymbol()
    {
        return symbol;
    }
}
        
Review of an Earlier Example (cont.)
javaexamples/oopbasics/finance/FutureQuotation.java
import java.util.GregorianCalendar;

/**
 * A future's contract quotation (i.e., open, high, low, close,
 * volume, and open interest).
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class FutureQuotation extends SecurityQuotation
{
    protected int              openInterest;
    protected String           commodity, month, year;

    /**
     * Explicit Value Constructor.
     *
     * @param commodity The commodity code
     * @param year      The year code
     * @param month     The month code
     * @param date      The date of the entry
     * @param open      The opening price
     * @param high      The high price
     * @param low       The low price
     * @param close     The closing price
     * @param volume    The volume traded
     */
    public FutureQuotation(String commodity, String year, String month, 
                           GregorianCalendar date, 
                           double open,double high,double low,double close,
                           int volume, int openInterest)
    {
        super(date, open, high, low, close, volume);

        this.commodity    = commodity;
        this.year         = year;
        this.month        = month;
        this.openInterest = openInterest;
    }

    /**
     * Return the open interest for this security.
     *
     * @return  The open interest
     */
    public int getOpenInterest()
    {
        return openInterest;
    }

    /**
     * Return the symbol for this security.
     *
     * @param symbol     The ticker symbol for this stock
     */
    public String getSymbol()
    {
        return commodity + year + month;        
    }

    /**
     * Return a String representation.
     *
     * @return   The String representation
     */
    public String toString()
    {
        return (super.toString()+"\tOI: " + openInterest);
    }
}
        
Our Current Objectives
Design 1
Approach 1 (cont.)

The constructor in SecurityQuotation is straightforward.

javaexamples/oopbasics/betterfinance/SecurityQuotation.java (Fragment: constructor)
    /**
     * Construct a SecurityQuotation from a String representation.
     *
     * @param s   The String representation
     */
    public SecurityQuotation(String s) 
        throws NoSuchElementException, NumberFormatException
    {
        int              dd, mm, yy;
        String           dds, mms, token, yys;
        StringTokenizer  tokenizer;


        tokenizer = new StringTokenizer(s,",");

        token = tokenizer.nextToken();
            
        yys = token.substring(0,2);
        yy  = Integer.parseInt(yys);
        
        mms = token.substring(2,4);
        mm  = Integer.parseInt(mms) - 1; // Note that months start with 0
        
        dds = token.substring(4);
        dd  = Integer.parseInt(dds);
        
        this.date = new GregorianCalendar(yy,mm,dd);
        
        token = tokenizer.nextToken();
        this.open = Double.parseDouble(token);
        
        token = tokenizer.nextToken();
        this.high = Double.parseDouble(token);
        
        token = tokenizer.nextToken();
        this.low = Double.parseDouble(token);
        
        token = tokenizer.nextToken();
        this.close = Double.parseDouble(token);
        
        token = tokenizer.nextToken();
        this.volume = Integer.parseInt(token);
    }
        
Approach 1 (cont.)

The constructor in StockQuotation is elegant.

javaexamples/oopbasics/betterfinance/StockQuotation.java (Fragment: constructor)
    /**
     * Set the attributes of this StockQuotation based on
     * a String representation.
     *
     * @param s       The String representation
     */
    public StockQuotation(String symbol, String s) 
        throws NoSuchElementException, NumberFormatException
    {
        super(s);
        this.symbol = symbol;
    }
        
Approach 1 (cont.)

The constructor in FutureQuotation is awful!

javaexamples/oopbasics/betterfinance/FutureQuotation.java (Fragment: constructor)
    /**
     * Set the attributes of this FutureQuotation based on
     * a String representation.
     *
     * @param commodity The commodity code
     * @param year      The year code
     * @param month     The month code
     * @param s         The String representation
     */
    public FutureQuotation(String commodity, String year, String month,
                                      String s) 
        throws NoSuchElementException, NumberFormatException
    {
        super(s);

        StringTokenizer tokenizer;
        tokenizer = new StringTokenizer(s, ",");
        for (int i=0; i<6; i++) tokenizer.nextToken();

        this.openInterest = Integer.parseInt(tokenizer.nextToken());

        this.commodity = commodity;
        this.year = year;
        this.month = month;
    }
        

It has to do unnecessary work and it has to know what work was done in the base class.

Design 2
Approach 2 (cont.)

The SecurityQuotation class now needs a default constructor (because the derived classes will), but it can be protected.

javaexamples/oopbasics/stillbetterfinance/SecurityQuotation.java (Fragment: constructor)
    /**
     * Default Constructor.
     *
     * To be used only by other constructors in this class and in
     * derived classes.
     */
    protected SecurityQuotation()
    {
        super();
    }
        
Approach 2 (cont.)

The code that was in the constructor can now be moved to the fromString() method (which can also be protected), and this method can return the StringTokenizer it used in case a derived class needs to use it.

javaexamples/oopbasics/stillbetterfinance/SecurityQuotation.java (Fragment: fromString)
    /**
     * Set the attributes of this SecurityQuotation based on
     * a String representation.
     *
     * @param s   The String representation
     * @return    The StringTokenizer in case it is needed by a derived class
     */
    protected StringTokenizer fromString(String s) 
        throws NoSuchElementException, NumberFormatException
    {
        int              dd, mm, yy;
        String           dds, mms, token, yys;
        StringTokenizer  tokenizer;


        tokenizer = new StringTokenizer(s,",");

        token = tokenizer.nextToken();
            
        yys = token.substring(0,2);
        yy  = Integer.parseInt(yys);
        
        mms = token.substring(2,4);
        mm  = Integer.parseInt(mms) - 1; // Note that months start with 0
        
        dds = token.substring(4);
        dd  = Integer.parseInt(dds);
        
        this.date = new GregorianCalendar(yy,mm,dd);
        
        token = tokenizer.nextToken();
        this.open = Double.parseDouble(token);
        
        token = tokenizer.nextToken();
        this.high = Double.parseDouble(token);
        
        token = tokenizer.nextToken();
        this.low = Double.parseDouble(token);
        
        token = tokenizer.nextToken();
        this.close = Double.parseDouble(token);
        
        token = tokenizer.nextToken();
        this.volume = Integer.parseInt(token);

        return tokenizer;        
    }
        
Approach 2 (cont.)

The StockQuotation class now needs a public default constructor (because someone that wants to create a StockQuotation from a String will first need to construct an empty object and then call its fromString()).

javaexamples/oopbasics/stillbetterfinance/StockQuotation.java (Fragment: constructor)
    /**
     * Default Constructor.
     *
     * Normally, the use of this constructor is followed immediately
     * by a call to fromString() to set the attributes.
     */
    public StockQuotation()
    {
        super();
    }
        
Approach 2 (cont.)

The fromString() method is now elegant because it can use the same StringTokenizer that the fromString() method in the SecurityQuotation class used.

javaexamples/oopbasics/stillbetterfinance/StockQuotation.java (Fragment: fromString)
    /**
     * Set the attributes of this StockQuotation based on
     * a String representation.
     *
     * @param symbol  The ticker symbol
     * @param s       The String representation
     * @return    The StringTokenizer in case it is needed by a derived class
     */
    public StringTokenizer fromString(String symbol, String s) 
        throws NoSuchElementException, NumberFormatException
    {
        StringTokenizer      tokenizer;

        this.symbol = symbol;
        tokenizer = super.fromString(s);

        return tokenizer;
    }
        
Approach 2 (cont.)

The FutureQuotation class also needs a public default constructor.

javaexamples/oopbasics/stillbetterfinance/FutureQuotation.java (Fragment: constructor)
    /**
     * Default Constructor.
     *
     * Normally, the use of this constructor is followed immediately
     * by a call to fromString() to set the attributes.
     */
    public FutureQuotation()
    {
        super();
    }
        
Approach 2 (cont.)

The fromString() method is now elegant because it can use the same StringTokenizer that the fromString() method in the SecurityQuotation class used.

javaexamples/oopbasics/stillbetterfinance/FutureQuotation.java (Fragment: fromString)
    /**
     * Set the attributes of this StockQuotation based on
     * a String representation.
     *
     * @param commodity The commodity code
     * @param year      The year code
     * @param month     The month code
     * @param s         The String representation
     */
    public StringTokenizer fromString(String commodity, String year, String month,
                                      String s) 
        throws NoSuchElementException, NumberFormatException
    {
        String                 token;        
        StringTokenizer        tokenizer;
        
        this.commodity    = commodity;
        this.year         = year;
        this.month        = month;

        tokenizer = super.fromString(s);
        token = tokenizer.nextToken();
        this.openInterest = Integer.parseInt(token);

        return tokenizer;
    }
        
Approach 2 (cont.)
Design 3
Approach 3 (cont.)

The default constructor in the StockQuotation class is now protected.

javaexamples/oopbasics/bestfinance/StockQuotation.java (Fragment: constructor)
    /**
     * Default Constructor.
     *
     * Normally, the use of this constructor is followed immediately
     * by a call to fromString() to set the attributes.
     */
    protected StockQuotation()
    {
        super();
    }
        
Approach 3 (cont.)

The fromString() method remains the same (though it could be made protected if desired) and a static factory method is added.

javaexamples/oopbasics/bestfinance/StockQuotation.java (Fragment: createInstance)
    /**
     * Parse a String representation of a StockQuotation into 
     * its components and construct a StockQuotation from them.
     *
     * @param s         The String representation
     */
    public static StockQuotation createInstance(String s) 
                                 throws NoSuchElementException,
                                        NumberFormatException
    {
        StockQuotation sq;
        sq = new StockQuotation();
        sq.fromString(s);
        return sq;
    }
        
Approach 3 (cont.)

The default constructor in the FutureQuotation class is now protected.

javaexamples/oopbasics/bestfinance/FutureQuotation.java (Fragment: constructor)
    /**
     * Default Constructor.
     *
     * Normally, the use of this constructor is followed immediately
     * by a call to fromString() to set the attributes.
     */
    protected FutureQuotation()
    {
        super();
    }
        
Approach 3 (cont.)

The fromString() method remains the same (though it could be made protected if desired) and a static factory method is added.

javaexamples/oopbasics/bestfinance/FutureQuotation.java (Fragment: createInstance)
    /**
     * Parse a String representation of a StockQuotation into 
     * its components and construct a StockQuotation from them.
     *
     * @param s         The String representation
     */
    public static FutureQuotation createInstance(String s) 
                                 throws NoSuchElementException,
                                        NumberFormatException
    {
        FutureQuotation fq;
        fq = new FutureQuotation();
        fq.fromString(s);
        return fq;
    }