Tutorial 2: JavaDoc, Package, Factory


Introduction

This tutorial covers:


I. Java Documentation Style

The Java Development Kit (JDK) comes with a tool called JavaDoc.  This tool will generate documentation for Java source code with comments written in accordance with the Java documentation style.  Chapter 11 of The Java Programming Language describe in details the JavaDoc documentation convention.  Take a quick look at the following links to see more examples.

Create a directory ~/comp212/tutorials/02 for this lab and copy the file ~comp212/hw/01/*.java.   These are the Java source code for the polynomial implementation.  They are documented according the JavaDoc convention.  Use your favorite editor to examine APolynomial.java.

Exercises:

  1. To run the javadoc utility, execute the command: javadoc *.java.   Appropriate html files will be generated.  What are the generated html files ?  Use a browser to view them.  Are the private fields and methods displayed?
    Now execute the command: javadoc -private *.java.  Can you see the difference?
  2. Create a directory ~/comp212/tutorials/02/images and copy the whole subdirectory ~comp212/hw/01/doc/images into the new directory.  The  images directory contains gif files used by JavaDoc for display purpose.  Reload (or refresh) the html files generated by JavaDoc to see a more colorful display of the documentation.
  3. Execute the command: javadoc.  You should see a brief description of the usage of javadoc.  Take a brief look at the explanation of the flags.

II. Package

A Java package is a grouping of classes similar to the notion of a directory is a grouping of files.  Packages are used to help avoid name clash and to hide particular pieces of code from the clients.  A package has a name, such as utility, or java.lang.util, etc.   In general, a package name has the form A followed by zero or more strings of the form .B where A and B are strings beginning with an alphabet character.  To make a java class part of a particular package, say poly, all you have to do is to add the statement package poly; to the very top of the class source file.

Exercises:

  1. Add the package poly; statement to the top of APolynomial.java.  Now try to compile APolynomial.java.  What happens?  You will need to create a subdirectory called poly and move APolynomial.java into the poly subdirectory.  Now go to poly and try to compile APolynomial.java again.  You should succeed this time.

  2. Add the package poly; statement to the top of ConstPoly.java and NonConstPoly.java.   Move these two files to poly.  Do not make PolyClient.java part of the poly package.  PolyClient.java does not have a package name.  It is said to be in the no-name (or default) package.   Leave PolyClient.java in the ~/comp212/tutorials/02 directory and try to compile it.  What happens?  You will need to add the statement import poly.*; to indicate to the compiler that you are using all the public classes in the poly packages.   Try to recompile PolyClient.java after adding the appropriate import statement.  You should a few error messages saying that you can't use ConstPoly.java and NonConstPoly.java because these classes are not public.   The PolyClient class is not part of the poly package.  You can resolve this problem by making PolyClient part of the poly package.  A class of a package can access all the classes (public or "package-private") in the package.  However this is not a good solution in general because a client may be using many classes from different packages and cannot be part of more than one package.  The next section will show you a better solution using a "factory".

    II. Factory

    Good software engineering practices advocate the principle of "information hiding": all implementation details should be hidden from client code.  In the case of our polynomial system,  ConstPoly.java and NonConstPoly.java are the details that clients should not know about.  The client should only program to the APolynomial abstraction.  For this reason ConstPoly.java and NonConstPoly.java are not public classes.  But the client needs to have a way to instantiate  ConstPoly  and NonConstPoly somehow.  The solution is to add a public class that is part of the poly package and that knows how to call the constructors for ta ConstPoly.java and NonConstPoly to manufacture these classes.  Such a class is called a factory in the language of design patterns.  The following is an example of such a class.

    package poly;
    /**
    *
    * Serves as a factory for manufacturing Polynomial objects.
    * @author Dung X. Nguyen
    * @since December 28, 1999
    */
    public class PolyFactory
    {
    /** @SBGen Variable (,Zero Polynomial,,64) */
        public final static APolynomial ZeroPoly = new ConstPoly (0.0);
    /**
    * Creates a constant Polynomial. Uses the flyweight pattern for the zero polynomial.
    * @return a constant Polynomial.
    */
    public static APolynomial MakeConstPoly (double coef)
    {
       return 0.0 == coef? ZeroPoly: new ConstPoly (coef);
    }

    /**
    * Creates a non-constant Polynomial with a given leading coefficient, a given degree,
    * and a given lower order polynomial. Checks for legal input parameters.
    * Will ignore zero leading coefficient.
    * @param coef the leading coefficient.
    * @param degree the degree, >= 0.
    * @param lowPoly != null, the lower ordered polynomial with degree < degree.
    * @return a non-constant Polynomial.
    * @exception throws IllegalArgumentException if conditions on degree and lowerPoly are violated.
    */
    public static APolynomial MakePoly (double coef, int degree, APolynomial lowerPoly)
    {
       if (degree <= 0)
       {
          throw new IllegalArgumentException ("Degree must be positive!");
       }
       if (null == lowerPoly)
       {
          throw new IllegalArgumentException ("lowerPoly must be non-null!");
       }
       if (0.0 == coef)
       {
          return lowerPoly;
       }
       if (degree <= lowerPoly.getDegree())
       {
          throw new IllegalArgumentException ("lowPoly is not a lower order term!");
       }
       return new NonConstPoly (coef, degree, lowerPoly);

    }

    /**
    * A few simple test cases.
    */
    public static void main (String[] args)
    {
       APolynomial pc0 = ZeroPoly; // pc0 == 0.
       APolynomial pc1 = MakeConstPoly (-1); // pc1 == -1.
       APolynomial p1 = MakePoly (-5, 3, pc0); // p1 == -5x^3.
       APolynomial p2 = MakePoly (2, 5, p1); // p2 == 2x^5 - 5x^3.
       APolynomial p3 = MakePoly (-4, 6, p2);
       APolynomial p4 = MakePoly (3, 2, pc1);
       System.out.println ("0 = " + pc0);
       System.out.println ("-1 = " + pc1);
       System.out.println ("3x^2 - 1 = " + p4);
       System.out.println ("-5x^3 + 0 = " + p1);
       System.out.println ("2x^5 - 5x^3 + 0 = " + p2);
       System.out.println ("-4x^6 + 2x^5 - 5x^3 + 0 = " + p3);
    }
    }

    Exercises:

    1. Modify PolyClient.java to use PolyFactory to create ConstPoly and NonConstPoly instead.  You can remove the code that checks for valid input parameters in the constructor for NonConstPoly.  Compile PolyClient and run it.

    2. Examine of ConstPoly.java and NonConstPoly.java and replace all calls to the constructors of  ConstPoly.java and NonConstPoly.java with appropriate calls to PolyFactory's creation methods.  Can you simplify the code for NonCosntPoly.add (...) a little ?  Compile and run PolyClient.java.
dxnguyen@cs.rice.edu
revised 01/30/00