JMU
Developing Classes
With Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Review
Classes
The Design and Implementation of Classes
Steps in the Process
  1. Create an initial encapsulation
  2. Refine the encapsulation
  3. Identify constructors
  4. Think about the need for private methods
  5. Identify helpful overloaded methods
  6. Identify class attributes
  7. Identify class behaviors
What's the Starting Point?
What's the Starting Point? (cont.)

An Example of a Textual Description

A picture frame is used to display a picture. It always has a width and height (measured in inches). It may or may not have a matte/border (also measured in inches). If it has a matte, it is the same size on all four sides. One can calculate the visible area of a picture frame from its area and the area of the matte.

A picture frame may or may not have a stand.

One can calculate the cost of a picture frame from the amount of material used in the perimeter of the frame itself and the area of the glass.

Creating the Initial Encapsulation
Creating the Initial Encapsulation (cont.)
  1. Make all instance attributes private
  2. Provide "get" methods (called accessors) where needed
  3. Provide "set" methods (one type of mutator) methods where needed
Creating the Initial Encapsulation (cont.)

An Example

A picture frame is used to display a picture. It always has a width and height (measured in inches). It may or may not have a matte/border (also measured in inches). If it has a matte, it is the same size on all four sides. One can calculate the visible area of a picture frame from its area and the area of the matte.

A picture frame may or may not have a stand.

One can calculate the cost of a picture frame from the amount of material used in the perimeter of the frame itself and the area of the glass.

Creating the Initial Encapsulation (cont.)

An Example

public class PictureFrame
{
    private double    width;
    private double    height;
    private double    matte;

    private boolean   stand;
    private boolean   hasMatte;

    public double calculateVisibleArea(){return 0.0;}
    public double calculateCost(){return 0.0;}
}
Refining the Encapsulation: Attributes
Refining the Encapsulation: Attributes (cont.)

Overuse of Instance Attributes

javaexamples/oopbasics/Screen.java
import java.io.*;
import java.text.*;

/**
 * A simple class that performs formatted output to the
 * console (i.e., standard output)
 *
 * Note: This class uses attributes in places where it would be
 *       better to use local variable 
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 2.0bad
 */
public class Screen
{
    private boolean               group;
    private int                   minLeft, maxLeft, minRight, maxRight;
    private NumberFormat          formatter;
    private OutputStreamWriter    osw;
    private PrintWriter           out;
    private String                formattedString, outputString;

    /**
     * Default Constructor
     */
    public Screen()
    {
        osw = new OutputStreamWriter(System.out);
        out = new PrintWriter(osw);
    }



   /**
     * Create a NumberFormatter object
     */
    private NumberFormat createFormatter()
    {
        formatter = NumberFormat.getInstance();
        formatter.setMinimumIntegerDigits(minLeft);
        formatter.setMaximumIntegerDigits(maxLeft);
        formatter.setMinimumFractionDigits(minRight);
        formatter.setMaximumFractionDigits(maxRight);
        formatter.setGroupingUsed(group);

        return formatter;
    }


    /**
     * Format an int as a String 
     *
     * @param  value  The int to format
     * @return        The appropriately formatted String
     */
    private String format(int value)
    {
        minLeft  =  0;
        maxLeft  = 15;
        minRight =  0;
        maxRight =  0;
        group    = false;
        formatter = createFormatter();
        formattedString = formatter.format(value);

        return formattedString;
    }




   /**
     * Print an int
     *
     * @param value   The value
     */
    public void printInt(int value)
    {
        outputString = format(value);
        out.print(outputString);
        out.flush();
    }

}
    
        
Refining the Encapsulation: Attributes (cont.)

Eliminating a Redundancy

public class PictureFrame
{
    private double    width;
    private double    height;
    private double    matte; // 0.0 when there is no matte

    private boolean   stand;

    public double calculateCost(){return 0.0;}
    public double calculateVisibleArea(){return 0.0;}
}
Refining the Encapsulation: Behaviors
Refining the Encapsulation

Adding equals() and toString() Methods

public class PictureFrame
{
    private double    width;
    private double    height;
    private double    matte; // 0.0 when there is no matte

    private boolean   stand;

    public double calculateCost(){return 0.0;}

    public double calculateVisibleArea(){return 0.0;}

    public boolean equals(PictureFrame other) {return false);

    public String toString(){return "";}
}
Identifying Constructors
Identifying Constructors (cont.)

An Example

javaexamples/oopbasics/pictureframe/start/PictureFrame.java
/**
 * An encapsulation of a picture frame.
 *
 * Note: The attributes are public in this version because we
 * have not yet discussed information hiding.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class PictureFrame
{
    public boolean    stand;    
    public double     height, matte, width;
    /**
     * Construct a PictureFrame object.
     *
     * Note: Negative values are converted to positive values 
     * and the width and height are put in canonical form 
     * (i.e., a portrait orientation).
     *
     * @param width   The width (in inches)
     * @param height  The height (in inches)
     * @param matte   The size of the matte (in inches) on all 4 sides
     * @param stand   true if there is a built-in stand
     */
    public PictureFrame(double width, double height, double matte, 
                        boolean stand)
    {
        double     h, w;
        
        h = Math.abs(height);
        w = Math.abs(width);

        this.width  = Math.min(w, h);
        this.height = Math.max(w, h);
        this.matte  = Math.abs(matte);
        this.stand  = stand;
    }
    /**
     * Return the cost of this PictureFrame (which is a function
     * of the perimeter and the area) in dollars.
     *
     * @return   The cost
     */
    public double calculateCost()
    {
        double     frame, glass;
        
        frame = (2.0*width + 2.0*height) * 0.15;
        glass = (width * height) * 0.05;

        return frame+glass;
    }

    /**
     * Return the visible area (in square inches) of the content
     * contained in this PictureFrame.
     *
     * @return   The visible area
     */
    public double calculateVisibleArea()
    {
        return (width - 2.0*matte) * (height - 2.0*matte);
    }
    /**
     * Return true if the owning PictureFrame and the given PictureFrame
     * have the same attributes.
     *
     * @return  true if the attributes are the same; false otherwise
     */
    public boolean equals(PictureFrame other)
    {
        return (this.width == other.width) && (this.height == other.height)
            && (this.matte == other.matte) && (this.stand == other.stand);
    }
    /**
     * Return a human-readable String representation of this PictureFrame.
     *
     * @return  The String representation
     */
    public String toString()
    {
        String      result;
        
        result = String.format("%5.2f in. x %5.2f in.", width, height);
        if (matte > 0.0)
            result += String.format(" with a %5.2f in. matte", matte);
        if (stand)
            result += " (w/ stand)";
        
        return result;
    }
}
        
Identifying Constructors (cont.)
Overloaded Constructors (cont.)
Overloaded Constructors (cont.)

Adding Copy, Default, and Explicit Value Constructors

javaexamples/oopbasics/pictureframe/overloadedconstructors/PictureFrame.java (Fragment: Constructors)
    /**
     * Construct a PictureFrame object.
     *
     * Note: Negative values are converted to positive values 
     * and the width and height are put in canonical form 
     * (i.e., a portrait orientation).
     *
     * @param width   The width (in inches)
     * @param height  The height (in inches)
     * @param matte   The size of the matte (in inches) on all 4 sides
     * @param stand   true if there is a built-in stand
     */
    public PictureFrame(double width, double height, double matte, 
                        boolean stand)
    {
        double     h, w;
        
        h = Math.abs(height);
        w = Math.abs(width);

        this.width  = Math.min(w, h);
        this.height = Math.max(w, h);
        this.matte  = Math.abs(matte);
        this.stand  = stand;
    }
    
    /**
     * Construct a PictureFrame object with no matte and no stand.
     *
     * @param width   The width (in inches)
     * @param height  The height (in inches)
     */
    public PictureFrame(double width, double height)
    {
        this(width, height, 0.0, false);
    }
    
    /**
     * Default Constructor.
     *
     * Construct a 3x5 PictureFrame with no matte and no stand.
     */
    public PictureFrame()
    {
        this(3.0, 5.0, 0.0, false);
    }
    
    /**
     * Copy Constructor.
     *
     * @param other   The PictureFrame to copy
     */
    public PictureFrame(PictureFrame other)
    {
        this(other.width, other.height, other.matte, other.stand);
    }
        
Overloaded Constructors (cont.)

A Common Mistake

    public PictureFrame(double width, double height, double matte, 
                        boolean stand)
    {
        double     h, w;
        
        h = Math.abs(height);
        w = Math.abs(width);

        this.width  = Math.min(w, h);
        this.height = Math.max(w, h);
        this.matte  = Math.abs(matte);
        this.stand  = stand;
    }
    
    public PictureFrame(double width, double height)
    {
        PictureFrame     frame;

        frame = new PictureFrame(width, height, 0.0, false);
    }
More on Copy Constructors
More on Copy Constructors (cont.)

In this example, since both of the attributes are primitive types, the distinction between shallow and deep copies does not arise.

javaexamples/basics/Pair.java (Fragment: CopyConstructor)
    /**
     * Copy Constructor
     */
    public Pair(Pair other)
    {
       this.a = other.a;
       this.b = other.b;
    }
        

If, for example, the Pair class included a String attribute named id, then a shallow copy would include the statement:

  this.id = other.id;              // this.id is an alias for other.id
  

whereas a deep copy would include the statement:

  this.id = new String(other.id);  // Use the copy constructor in String
  
Identifying Useful Private Methods
Private Methods (cont.)
javaexamples/oopbasics/pictureframe/privatemethods/PictureFrame.java
/**
 * An encapsulation of a picture frame.
 *
 * This version has overloaded methods.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 6.0
 */
public class PictureFrame
{
    private static final double DOLLARS_PER_IN_OF_FRAME    = 0.15;
    private static final double DOLLARS_PER_SQ_IN_OF_GLASS = 0.05;    

    private boolean    stand;    
    private double     height, matte, width;

    /**
     * Construct a PictureFrame object.
     *
     * Note: Negative values are converted to positive values 
     * and the width and height are put in canonical form 
     * (i.e., a portrait orientation).
     *
     * @param width   The width (in inches)
     * @param height  The height (in inches)
     * @param matte   The size of the matte (in inches) on all 4 sides
     * @param stand   true if there is a built-in stand
     */
    public PictureFrame(double width, double height, double matte, 
                        boolean stand)
    {
        double     h, w;
        
        h = Math.abs(height);
        w = Math.abs(width);

        this.width  = Math.min(w, h);
        this.height = Math.max(w, h);
        this.matte  = Math.abs(matte);
        this.stand  = stand;
    }
    
    /**
     * Construct a PictureFrame object with no matte and no stand.
     *
     * @param width   The width (in inches)
     * @param height  The height (in inches)
     */
    public PictureFrame(double width, double height)
    {
        this(width, height, 0.0, false);
    }
    
    /**
     * Default Constructor.
     *
     * Construct a 3x5 PictureFrame with no matte and no stand.
     */
    public PictureFrame()
    {
        this(3.0, 5.0, 0.0, false);
    }
    
    /**
     * Copy Constructor.
     *
     * @param other   The PictureFrame to copy
     */
    public PictureFrame(PictureFrame other)
    {
        this(other.width, other.height, other.matte, other.stand);
    }

    /**
     * Calculate the area of this PictureFrame.
     *
     * @return  The area (in square inches)
     */
    private double area()
    {
        return width * height;
    }

    /**
     * Calculate the area of the matte.
     *
     * @return  The area (in square inches)
     */
    private double matteArea()
    {
               // Top and Bottom   + Sides (not including the top and bottom)
        return 2.0*(matte * width) + 2.0*(matte * (height - 2.0*matte));
    }

    /**
     * Calculate the perimeter of this PictureFrame.
     *
     * @return  The area (in inches)
     */
    private double perimeter()
    {
        return 2.0*width + 2.0*height;
    }

    /**
     * Return true if the owning PictureFrame and the given PictureFrame
     * have the same attributes.
     *
     * @return  true if the attributes are the same; false otherwise
     */
    public boolean equals(PictureFrame other)
    {
        return (this.width == other.width) && (this.height == other.height)
            && (this.matte == other.matte) && (this.stand == other.stand);
    }

    /**
     * Return the cost of this PictureFrame (which is a function
     * of the perimeter and the area) in dollars.
     *
     * @return   The cost
     */
    public double getCost()
    {
        double     frame, glass;
        
        frame = perimeter() * DOLLARS_PER_IN_OF_FRAME;
        glass = area() * DOLLARS_PER_SQ_IN_OF_GLASS;

        return frame+glass;
    }

    /**
     * Get the height of this PictureFrame.
     *
     * @return   The height
     */
    public double getHeight()
    {
        return height;
    }

    /**
     * Get the size of the matte.
     *
     * @return   The size of the matte
     */
    public double getMatte()
    {
        return matte;
    }

    /**
     * Get the width of this PictureFrame.
     *
     * @return   The width
     */
    public double getWidth()
    {
        return width;
    }
    /**
     * Return the visible area (in square inches) of the content
     * contained in this PictureFrame.
     *
     * @param    max   true for the maximum possible (i.e., unmatted) area 
     * @return   The visible area
     */
    public double getVisibleArea(boolean max)
    {
        double   result;
        
        result = area();
        if (!max) result -= matteArea();

        return result;
    }

    /**
     * Return the visible area (in square inches) of the content
     * contained in this PictureFrame.
     *
     * @return   The visible area
     */
    public double getVisibleArea()
    {
        return getVisibleArea(false);
    }

    /**
     * Return a human-readable String representation of this PictureFrame.
     *
     * @param   terse  true for a terse representation
     * @return         The String representation
     */
    public String toString(boolean terse)
    {
        String      result;

        if (terse)
        {
            result = ""+width+"x"+height;
        }
        else
        {
            result = ""+width+"in. x "+height+"in.";
            if (matte > 0.0) result += " with a "+matte+"in. matte";
            if (stand)       result += " (w/ stand)";
        }
        
        return result;
    }

    /**
     * Return a human-readable String representation of this PictureFrame.
     *
     * @return         The String representation
     */
    public String toString()
    {
        return toString(false);
    }
}
        
Identifying Helpful Overloaded Methods
Overloaded Methods: An Example
javaexamples/oopbasics/pictureframe/overloadedmethods/PictureFrame.java (Fragment: overloadedmethods)
    /**
     * Return the visible area (in square inches) of the content
     * contained in this PictureFrame.
     *
     * @param    max   true for the maximum possible (i.e., unmatted) area 
     * @return   The visible area
     */
    public double getVisibleArea(boolean max)
    {
        double   result;
        
        result = area();
        if (!max) result -= matteArea();

        return result;
    }

    /**
     * Return the visible area (in square inches) of the content
     * contained in this PictureFrame.
     *
     * @return   The visible area
     */
    public double getVisibleArea()
    {
        return getVisibleArea(false);
    }

    /**
     * Return a human-readable String representation of this PictureFrame.
     *
     * @param   terse  true for a terse representation
     * @return         The String representation
     */
    public String toString(boolean terse)
    {
        String      result;

        if (terse)
        {
            result = ""+width+"x"+height;
        }
        else
        {
            result = ""+width+"in. x "+height+"in.";
            if (matte > 0.0) result += " with a "+matte+"in. matte";
            if (stand)       result += " (w/ stand)";
        }
        
        return result;
    }

    /**
     * Return a human-readable String representation of this PictureFrame.
     *
     * @return         The String representation
     */
    public String toString()
    {
        return toString(false);
    }
        
Overloaded Methods: Common Uses
Overloaded Methods: Default Handling
Overloaded Methods: Default Handling (cont.)

An Example

public class TaxStand
{
      .
      .
      .

    /** 
     * Calculates the tax payment based on income and
     * filing status
     */
     public double payment(int income, int status)
     {
             ...
     }

     /**
      * Calculates the tax payment assuming the
      * filing status is 0
      */
      public double payment(int income)
      {
          return payment(income, 0);
      }
 }
Overloaded Methods: Similar Types
Overloaded Methods: Similar Types (cont.)

An Example

public class Weight
{
    .
    .
    .

    /**
     * Change this Weight by a given amount
     *
     * @param amount   The amount of the change
     */
     public void changeBy(Weight amount)
     {
        ...
     }


    /**
     * Change this Weight by a given amount
     *
     * @param pounds   Number of pounds in the change
     * @param ounces   Number of ounces in the change
     * @param positive true to increase, false to decrease
     */
     public void changeBy(int pounds, int ounces, boolean positive)
     {
           ...
     }
}
Overloaded Methods: Similar Types (cont.)

An Example

public class TaxStand
{
          .
          .
          .
      /** 
       * Calculates the tax payment based on income and
       * filing status
       */
       public double payment(int income, int status)
       {
             ...
       }


      /** 
       * Calculates the tax payment based on income and
       * filing status
       */
       public double payment(double income, int status)
       {
             ...
       }

}
Overloaded Methods: Similar Types (cont.)
Overloaded Methods: Cardinality
Overloaded Methods: Cardinality (cont.)

An Example

public int minimum(int a, int b)
{
    int min;

    min = a;
    if (b <  a) min = b;

    return b;
}

public int minimum(int[] values)
{
    int min;

    min = values[0];
    for (i=1; i < values.length; i++)
    {
        if (values[i] <  min) min = values[i];
    }

    return min;
}
Identifying Class Attributes
Class Attributes: Common Uses
Class Attributes: Constants etc...
Class Attributes: Constants etc... (cont.)
javaexamples/oopbasics/pictureframe/staticattributes/PictureFrame.java (Fragment: staticattributes)
    private static final double DOLLARS_PER_IN_OF_FRAME    = 0.15;
    private static final double DOLLARS_PER_SQ_IN_OF_GLASS = 0.05;    
    /**
     * Return the cost of this PictureFrame (which is a function
     * of the perimeter and the area) in dollars.
     *
     * @return   The cost
     */
    public double getCost()
    {
        double     frame, glass;
        
        frame = perimeter() * DOLLARS_PER_IN_OF_FRAME;
        glass = area() * DOLLARS_PER_SQ_IN_OF_GLASS;

        return frame+glass;
    }
        
Class Attributes: Common Values

An Example

public class ProgressiveSlotMachine
{
    // Attributes of the class
    private static double      jackpot;


    // Attributes of objects
    private double             currentBet;

    .
    .
    .


    private void handleLosingSpin()
    {
        jackpot = jackpot + 0.5 * currentBet;
    }
}
  
Class Attributes: Object Counters

An Example

/**
 * A user account
 */
public class UserAccount
{
    // Attributes of the class
    private static   int              nextAccountNumber;


    // Attributes of objects
    protected final  int              accountNumber;
    protected        String           name;



    /**
     * Explicit Value Constructor
     *
     * @param name   The name of the account holder
     */
    public UserAccount(String name)
    {
        // Store the name
        this.name    = name;

        // Store the account number
        accountNumber    = nextAccountNumber;

	// Setup the account number for the next account
        nextAccountNumber++;
    }
  
Identifying Class Methods
Class Methods: Common Uses
Class Methods: Utility Classes
Class Methods: System Calls
Class Methods: "Factory" Methods
Class Methods: "Factory" Methods (cont.)

A parsePictureFrame() Method in the PictureFrame Class

javaexamples/oopbasics/pictureframe/factories/PictureFrame.java (Fragment: parse)
    /**
     * Create a PictureFrame object from a comma-delimited
     * String representation.
     *
     * @param s   The String representation
     * @return    The PictureFrame object (or null)
     */
    public static PictureFrame parsePictureFrame(String s)
    {
        double               height, matte, width;        
        PictureFrame         result;        
        String               token;        
        StringTokenizer      st;
        
        st = new StringTokenizer(s, ",");
        try
        {
            token = st.nextToken();
            width = Double.parseDouble(token);
            
            token = st.nextToken();
            height = Double.parseDouble(token);

            token = st.nextToken();
            matte = Double.parseDouble(token);
            
            token = st.nextToken();
            result = new PictureFrame(width, height, matte,
                                      token.equalsIgnoreCase("TRUE"));
        }
        catch (NumberFormatException nfe)
        {
            result = null;
        }
        catch (NoSuchElementException msee)
        {
            result = null;
        }

        return result;
    }
        
"Factory" Methods vs. Constructors