Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

OOD -- The Painter's Canvas Problem

Java Programming, Lecture Notes # 031, Revised 10/02/99.

Preface
Introduction
Sample Program from Dale and Weems
Description of the Problem
OOD Solution
Discussion
Required Classes, Objects, and Instance Variables
Required Methods
Relationships Among Classes and Objects
Behavior of Objects
Interesting Code Fragments
Program Listing

Preface

Students in Prof. Baldwin's Introductory Java Programming classes at ACC are responsible for knowing and understanding all of the material in this lesson.

Introduction

A very brief description of Object-Oriented Design (OOD) was presented in Lesson 4 along with an example of using OOD to develop a simple program that simulated a digital counter. Additional material on the topic was provided in lesson 29 which discussed the topic in considerably more detail.

This lesson, and others that follow will continue exposing you to OOD concepts and sample programs developed using OOD methodology so that you can learn about OOD as you learn to write object-oriented Java programs.

An overall objective in OOD is to create a model of the problem domain consisting of a set of cooperating objects. In order to create such a model, you must discover the classes/objects that make up the model, the attributes of the objects, the relationships among the objects, and the behavior of the objects.

One common technique for accomplishing this is to create a narrative description of the solution to the problem, and then use the nouns, adjectives, and verbs to help identify the classes, data members, and methods needed in the design. This or a similar methodology is found in many books on the subject.

Sample Program from Dale and Weems

This is a Java object-oriented solution to the Problem-Solving Case Study presented on page 152 of Turbo Pascal, Fourth Edition by Nell Dale and Chip Weems.

This sample program is being provided to contrast the structure of two different versions of the same program: one designed according to Top-Down Design methodology and the other designed according to Object-Oriented Design methodology.

Since I am not at liberty to reproduce the Top-Down solution in the textbook, in order for you to compare the two versions, you will need to see the version in the textbook. This series of textbooks has been in use at colleges and universities for many years, and hopefully you can locate one in a library, a friend's house, or a used book store.

Description of the Problem

The description of the problem is paraphrased below:

You are learning to make your own painting frames by stretching canvas over a wooden frame and tacking it to the back of the frame. For a given size of painting, you must determine how much wood to buy for the frame, how large a piece of canvas to purchase, and the cost of the materials. Write a program using OOD methodology that will perform that task.

Get the following input from the user:

Calculate and display the following output for the user:

Givens:

OOD Solution

The controlling class for the program is named Ood03. It is designed to run as a Java application which means that it requires a main() method. An instance of the controlling class is analogous to a painting.

Note: When I run this program under JDK 1.1.6, the prompts do not always appear on the screen at the correct point in time. However, if I ignore that situation and enter data just as though the prompt did correctly appear, all of the prompts eventually appear on the screen. I don't believe that this was a problem with JDK 1.1.3, but I'm not absolutely certain.

Discussion

The required classes, objects, and instance variables were discovered by analyzing the nouns in the description of the problem.

The required methods were discovered by analyzing the verbs and the output requirements in the description of the problem.

Required Classes, Objects, and Instance variables

The nouns that were selected to represent classes (and objects) were:

The nouns that were selected to represent instance variables of the Painting class were:

Note that these are objects of two of the three classes.

The nouns that were selected to represent instance variables of the Canvas class were:

The nouns that were selected to represent instance variables of the WoodenFrame class were:

Required methods

The verbs and other aspects of the description of the problem suggested that the Painting class should have the following methods including the main() method required by all Java applications:

Note that the Painting class is actually represented by the controlling class which, for disk storage reasons, was named Ood03 instead of Painting.

The verbs and other aspects of the description of the problem suggested that the Canvas class should have the following mutator methods. A mutator method is a method that modifies the value of an instance variable.

The description of the problem suggested that the Canvas class should have the following accessor methods. An accessor method is a method that uses, but does not modify the values of the instance variables.

The verbs and other aspects of the description of the problem suggested that the WoodenFrame class should have the following mutator methods:

The description of the problem suggested that the WoodenFrame class should have the following accessor methods:

Relationships Among Classes and Objects

The description of the problem suggested the following relationships among objects instantiated from the classes Ood03, Canvas, and WoodenFrame:

Each object of type Ood03 (Painting) contains one Canvas object and one WoodenFrame object. This is a has-a relationship. (A painting has a Canvas and a painting has a WoodenFrame.)

Behavior of Objects

The behavior of each of the objects of the Canvas, and WoodenFrame classes consists primarily of mutation and access.

Mutator methods are used to store information in the instance variables of the objects. Accessor methods are used to calculate and return higher-level representations of the instance variables such as total cost.

The behavior of an object of the Ood03 class requires

Interesting Code Fragments

One of the most significant things about objects designed according to the OOD methodology is that objects are generally self-contained entities. For example, in a sorting program, an object can tell you whether it is greater than, equal to, or less than another object of the same class.

That characteristic manifests itself in this program as well. Objects of the Canvas and WoodenFrame class know how to determine the cost of their materials for a painting of a specified size. An object of the Ood03 (painting) class knows how to determine the total cost of materials to construct an instance of itself. Objects store information, and they are able to answer questions about themselves.

We will begin our examination with the Ood03 class. This class represents a painting. It has a WoodenFrame object and it has a Canvas object, each represented by an instance variable.

It can get user input to establish its own size and can pass that information along to the WoodenFrame object and the Canvas object by sending them appropriate messages.

It can display important attributes about itself, including the total cost of materials required to construct one instance of itself.

This class has two instance variables, which are actually objects of the other two classes. The beginning of the class definition containing the two instance variables is shown in the following fragment.

public class Ood03{//controlling class
  private Canvas canvas = new Canvas();
  private WoodenFrame woodenFrame = new WoodenFrame();

All Java applications require a main() method in the controlling class. In this case, code in main() instantiates an object of itself which represents a painting.

Then the code in main() invokes input and output methods on the object, first to obtain size and unit cost information from the user, and second to report total size and total cost information back to the user.

  public static void main(String[] args){
    Ood03 painting = new Ood03();
    painting.getInput();
    painting.showOutput();
  }//end main

Now let's examine the getInput() method of the Ood03 (painting) class that gets input information from the user.

The first statement in this method instantiates a utility object of type EasyIn to make it easier to handle keyboard input. There is nothing about the EasyIn class that is peculiar to this design. It should be viewed as a local class library.

(However, you may find it interesting as an example program from a noted author illustrating to how to use the reader/writer character stream classes that were introduced in JDK 1.1.)

Then a temporary variable of type double is declared to use for a variety of purposes.

  private void getInput(){
    EasyIn easy = new EasyIn();
    double temp;//temporary double variable

This is followed by several groups of statements that are used to communicate with the user and also to communicate with two of the objects in the program. The following code fragment is typical of the code in each of these groups.

First, the method sends a prompt to the user asking her to enter the length of the painting in inches. The length is read from the keyboard as a double.

Then the method sends a message to the Canvas object telling it to change it state by storing the length of the painting in one of its instance variables.

In Java, the act of sending a message to an object is carried out by invoking a method on the object. In this case, we invoke the mutator method named setLength().

Similarly, a message is sent to the WoodenFrame object telling it to change its state and store the length of the painting in one of its instance variables.

Note that I considered defining a class and instantiating an object to represent the length and width of a painting to prevent having duplicate data in the Canvas and WoodenFrame objects. However, I decided that in this case, the amount of duplicated data wasn't sufficiently large to warrant the additional overhead involved with another object.

I also considered collecting the common attributes of length and width into a superclass and extending that class to create the classes named Canvas and WoodenFrame. However, I decided that wouldn't add benefit to the design at this level and didn't do it.

    System.out.println(
      "Enter length of painting in inches");
    temp = easy.readDouble();
    canvas.setLength(temp);
    woodenFrame.setLength(temp);

The getInput() method continues prompting the user for information and sending that information to the Canvas and WoodenFrame objects until all of the necessary input information has been obtained and stored in objects of those two classes. You can see the code for that activity in the complete listing of the program that follows this section.

That concludes the discussion of the getInput() method.

The showOutput() method of the Ood03 class, and the method named getTotalMaterialCost() (also of the Ood03 class) which is invoked by the showOutput() method are used to obtain information from the Canvas and WoodenFrame objects regarding their material requirements and the cost of those materials for a painting of the size specified earlier by the user.

The information obtained from the Canvas and WoodenFrame objects is displayed for the benefit of the user by the showOutput() method.

The method begins by sending a message to the WoodenFrame object asking it to report on the amount of wood that needs to be purchased to construct one instance of itself of the specified size. The method displays this information for the benefit of the user.

This communication is accomplished by invoking the getTotalLengthToBuy() accessor method on the WoodenFrame object as shown below. This method uses the information stored in the instance variables of the object to calculate and return the answer.

The method call is physically inside the parameter list of a call to the println() method. The println() method is a method of the System class that causes its argument to be displayed on the standard output device. In this case, the argument is the value returned by the call to getTotalLengthToBuy() and that value is displayed on the standard output device.

  private void showOutput(){
    System.out.println("Length of wood to buy is: " 
         + woodenFrame.getTotalLengthToBuy() + " inches");

Several more similar statements are executed where information is obtained from the Canvas and WoodenFrame objects and displayed on the output screen for the benefit of the user.

Then the painting objects sends a message to itself asking itself to report on the total material cost. This is accomplished when the object invokes the getTotalMaterialCost() method on itself.

getTotalMaterialCost() sends messages to the WoodenFrame and Canvas objects asking them to report on their individual costs. The method adds those individual costs and returns the sum of the individual costs as the total cost for the project.

The total cost is displayed for the benefit of the user, as shown below, and that terminates the showOutput() method.

    System.out.println("Total cost: " 
               + this.getTotalMaterialCost() + " dollars");

The next code fragment shows the getTotalMaterialCost() method of the Ood03 class that is used to calculate the total cost of the project. As mentioned above, this method sends messages to the WoodenFrame and Canvas objects asking them to return their individual total costs. The method adds these individual costs and returns the sum as the total material cost for the project.

  private double getTotalMaterialCost(){
    return (canvas.getTotalCost() 
                            + woodenFrame.getTotalCost());
  }//end getTotalMaterialCost()

That ends the discussion of the Ood03 class that represents a Painting object in this program. The Painting object knows enough about itself to be able to determine and display critical information about itself for a specified painting size and specified unit costs for the raw materials.

Next we will discuss the Canvas class.

The Canvas class represents the material used to cover the wooden frame for a painting. It has the following instance variables.

The length and width values represent the length and width of the painting and are used to calculate the actual length and actual width requirements of the piece of canvas material.

It also has a symbolic constant named margin which specifies the amount of extra material needed to wrap the canvas around the frame and staple it on the back.

The class uses mutator methods to set the values of the instance variables.

It does not provide field accessors by which the values of the instance variables can be obtained.

However, it knows how to calculate the total material cost for one instance of itself, and it provides accessor methods by which the following higher-level representations of the instance variables can be obtained:

The beginning of the class definition along with the symbolic constant and the instance variables is shown in the following fragment.

class Canvas{
  private final double margin = 5.0;
  private double length; //length of the painting
  private double width; //width of the painting
  private double costPerSqFt; //cost of the canvas  

The next code fragment shows the three mutator methods by which the values of the instance variables can be set. As you can see, they are very simple which is frequently the case.

  public void setLength(double length){
    this.length = length;
  }//end setLength()
  //-----------------------------------------------------//
  
  public void setWidth(double width){
    this.width = width;
  }//end setWidth()
  //-----------------------------------------------------//
  
  public void setCostPerSqFt(double costPerSqFt){
    this.costPerSqFt = costPerSqFt;
  }//end setCostPerSqFt()

The following code fragment shows the accessor methods by which an object of the class can calculate and return a higher-level representation of the values of the instance variables (such as total length).

In this case, total length is the length of the painting plus the binding margin required to fold the canvas under the frame and staple it. Similarly, total width is the width of the painting plus the binding margin.

Note that the third accessor method was required to make a conversion between square inches and square feet; hence the use of the constant 144 (there are 144 square inches in a square foot).

  public double getTotalLength(){
    return (length + margin);
  }//end getTotalLength()
  //-----------------------------------------------------//
 
  public double getTotalWidth(){
    return (width + margin);
  }//end getTotalWidth()
  //-----------------------------------------------------//
  
  public double getTotalCost(){
    return (
     (((length+margin) * (width+margin))*costPerSqFt)/144);
  }//end getTotalCost()

That ends the discussion of the Canvas class.

The one remaining class to be discussed is the WoodenFrame class.

This class represents the wooden frame that is covered with canvas for a painting. It has the following instance variables:

Note that length and width are the length and width of the painting which is the same as the length and width required of a finished frame. The costPerInch is the cost of the wood required to construct the frame measured in inches along the length of the board.

The WoodenFrame class uses mutator methods to set the values of the instance variables.

As with the Canvas class, it does not provide field accessors by which the values of the instance variables can be read.

However, it knows how to calculate the total material cost for one instance of itself, and provides accessor methods by which the following higher-level representations of the instance variables can be obtained:

The following code fragment shows the beginning of the class along with the three instance variables.

class WoodenFrame{
  private double length; //of the painting  
  private double width; //of the painting
  private double costPerInch; //for the wood

The mutator methods used to set the values of the instance variables are shown in the next code fragment.

  public void setLength(double length){
    this.length = length;
  }//end setLength()
  //-----------------------------------------------------//
  
  public void setWidth(double width){
    this.width = width;
  }//end setWidth()
  //-----------------------------------------------------//
  
  public void setCostPerInch(double costPerInch){
    this.costPerInch = costPerInch;
  }//end setCostPerInch()

The accessor methods required to calculate and return the specified information are shown in the next fragment.

Note that the total length of the wood required to build a frame is twice the sum of the length and the width of the frame.

The total cost is the product of the total length in inches and the costPerInch of the wood.

  public double getTotalLengthToBuy(){
    return (2*(length + width));
  }//end getTotalLengthToBuy()
  //-----------------------------------------------------//
  
  public double getTotalCost(){
    return ((2*(length + width))*costPerInch);
  }//end getTotalCost()

That ends the discussion of the WoodenFrame class.

In summary, object-oriented design leads to designs where the solution to the programming problem is to have two or more objects that send messages to each other and react to messages sent by others.

A message from one object typically tells another object to either change its state, perform an action, or both.

In this program, we used mutator methods to tell an object to change its state. When we invoked those mutator methods, we provided the information necessary to define the new state of the object.

We used accessor methods to tell an object to perform an action. In this program, the action to be performed was to calculate a value making use of the values stored in the instance variables of the object. Those values were placed there earlier using the mutator methods.

If possible, you should obtain a copy of the textbook listed above and compare this solution with the Top-Down solution provided in that book. For small programs like this one, neither approach is significantly advantageous relative to the other. However, for a variety of reasons, as the size of the program grows, the advantages of Object-Oriented Design over Top-Down Design begin to manifest themselves.

You should probably learn how to use OOD methodology to design small programs before you tackle larger programs.

Program Listing

A complete listing of the program follows.

/*File Ood03.java Copyright 1997, R.G.Baldwin
This is a Java object-oriented solution to the Problem- 
Solving Case Study on page 152 of Turbo Pascal, Fourth 
Edition by Nell Dale and Chip Weems. 

This sample program is being provided to contrast the 
structure of two different versions of the program: one 
designed according to Top-Down Design methodology as 
provided in the book, and the other designed according
to Object-Oriented Design methodology.

The description of the problem is paraphrased below:

You are learning to make your own painting frames by 
stretching the canvas over a wooden frame and tacking 
it to the back of the frame. For a given size of 
painting, you must determine how much wood to buy for 
the frame, how large a piece of canvas to purchase, and 
the cost of the materials. Write a program using OOD 
methodology that will perform that task.

Input: 

    Length and width of the painting, 
    Cost per inch for the wood, and 
    Cost per square foot for the canvas.

Output: 

    Prompting messages, 
    Echo of input data, 
    Amount of wood to buy in inches, 
    Dimensions of the canvas in inches, 
    Cost of the wood in dollars,
    Cost of the canvas in dollars, and 
    Total cost of the materials in dollars.

Givens:

    The required length of the wood to build a frame is 
      twice the sum of the width and the length of the 
      painting assuming no waste.
    The size of the canvas must be 5 inches greater 
      than the size of the painting in both dimensions in 
      order to allow for wrapping and tacking of the 
      canvas to the wooden frame.
    The user will provide proper input data so that no 
      error checking on input is required.

Solution:

The controlling class for the program is named Ood03. 
It is designed to run as a Java application which means 
that it requires a main method. An instance of the 
controlling class is analogous to a painting.

Discussion:

The required classes, objects, and instance variables 
were discovered by analyzing the nouns in the 
description of the problem..

The required methods were discovered by analyzing the 
verbs and the output requirements in the description of 
the problem.

Required classes, objects, and instance variables:

The nouns that were selected to represent classes (and 
objects) were: 

    Painting
    Canvas
    WoodenFrame.

The nouns that were selected to represent instance 
variables (instance objects) of the Painting class 
were: 

    Canvas
    WoodenFrame.

The nouns that were selected to represent instance 
variables of the Canvas class were: 

    Margin (the folding margin)
    Length (the length of the painting)
    Width (the width of the painting)
    Cost Per Sq Ft (the cost of the canvas material)

The nouns that were selected to represent instance 
variables of the WoodenFrame class were: 

    Length (the length of the painting)
    Width (the width of the painting)
    Cost Per Inch (the cost of the wood)

Required methods:

The verbs and other aspects of the description of the 
problem suggested that the Painting class should have 
the following methods including the main method 
required by all Java applications:

    main()
    getInput()
    showOutput()
    getTotalMaterialCost()

Note that the Painting class is actually represented by 
the controlling class which, for disk storage reasons, 
is named Ood03 instead of Painting.

The verbs and other aspects of the description of the 
problem suggested that the Canvas class should have the 
following mutator methods:

    setLength(double length)
    setWidth(double width)
    setCostPerSqFt(double costPerSqFt)

The description of the problem suggested that the 
Canvas class should have the following accessor 
methods:

    getTotalLength()
    getTotalWidth()
    getTotalCost()

The verbs and other aspects of the description of the 
problem suggested that the WoodenFrame class should 
have the following mutator methods:

    setLength(double length)
    setWidth(double width)
    setCostPerInch(double costPerInch)

The description of the problem suggested that the 
WoodenFrame class should have the following accessor 
methods:

    getTotalLengthToBuy()
    getTotalCost()

Relationships among classes and objects:

The description of the problem suggested the following 
relationships among objects instantiated from the 
classes Ood03, Canvas, and WoodenFrame:

Each object of type Ood03 (Painting) contains one 
Canvas object and one WoodenFrame object. This is a 
has-a relationship. (A painting has-a Canvas and a
painting has-a WoodenFrame.)

Behavior of Objects:

The behavior of each of the objects of the Canvas, and 
WoodenFrame classes consists primarily of mutation and 
access. Mutator methods are used to store information 
in the instance variables of the objects. Accessor 
methods are used to calculate and return higher-level 
representations of the instance variables such as total 
cost. 

The behavior of an object of the Ood03 class requires 

    Getting input data from the user, 
    Sending messages to the Canvas and WoodenFrame 
      objects asking them to change their state and store 
      the information obtained from the user, 
    Sending messages to the Canvas and WoodenFrame 
      objects asking them to calculate and return 
      information in the form of higher-level 
      representations of the data stored in their 
      instance variables (such as total cost), and
    Displaying data provided by those objects for the 
      benefit of the user.

The program was tested using JDK 1.1.3 running under Win95.
**********************************************************/

import java.io.*;
import java.util.*;
//=======================================================//
public class Ood03{//controlling class
  //This class represents a painting.  It has a WoodenFrame
  // object and it has a Canvas object, each represented
  // by an instance variable. It can get user input to
  // establish its own size in order to pass that 
  // information along to the WoodenFrame object and the 
  // Canvas object.  It can display all the important
  // attributes about itself, including the total cost
  // of materials required for one instance of itself.

  //Instance variables
  private Canvas canvas = new Canvas();
  private WoodenFrame woodenFrame = new WoodenFrame();
  //-----------------------------------------------------//
  
  //Methods
  //-----------------------------------------------------//

  //All Java applications require a main method in the
  // controlling class.
  public static void main(String[] args){
    //Instantiate a new painting object.
    Ood03 painting = new Ood03();
    
    //Get size information about the painting and unit
    // cost information for the materials required to 
    // assemble the frame and canvas for the painting.
    painting.getInput();
    
    //Display information on total material requirements
    // and total cost.
    painting.showOutput();
  }//end main
  //-----------------------------------------------------//

  private void getInput(){
    //This method is used to obtain information about the
    // size of the painting and the unit cost for required
    // materials.
    
    //Prepare to use the class that supports keyboard input
    EasyIn easy = new EasyIn();
    
    double temp;//temporary double variable

    //Display a prompt to the user.    
    System.out.println(
      "Enter length of painting in inches");
    
    //Get the length of the painting from the user.
    temp = easy.readDouble();
    
    //Send a message to the Canvas object telling it to
    // change its state to include the length of the
    // painting.
    canvas.setLength(temp);
    
    //Send a message to the WoodenFrame object telling it
    // to change its state to include the length of the
    // painting.
    woodenFrame.setLength(temp);
    
    //Continue getting input information and sending
    // messages to the Canvas object and the WoodenFrame
    // object telling them to change their state to
    // include the new information.
    System.out.println(
      "Enter width of painting in inches");
    temp = easy.readDouble();
    canvas.setWidth(temp);
    woodenFrame.setWidth(temp);
    
    System.out.println("Enter cost per inch for wood");
    temp = easy.readDouble();
    woodenFrame.setCostPerInch(temp);
    
    System.out.println("Enter cost per sq ft for canvas");
    temp = easy.readDouble();
    canvas.setCostPerSqFt(temp);
  }//end getInput()
  //-----------------------------------------------------//
  
  private void showOutput(){
    //This method, and the method called by this method
    // named getTotalMaterialCost are used to obtain 
    // information from the Canvas object and the 
    // WoodenFrame object regarding their material 
    // requirements and the cost of that material.  The
    // information so obtained is displayed for the benefit
    // of the user.
    
    //Send a message to the WoodenFrame object asking it
    // to report on the amount of wood that needs to be
    // purchased.  Display this information for the 
    // benefit of the user.
    System.out.println("Length of wood to buy is: " 
         + woodenFrame.getTotalLengthToBuy() + " inches");
         
    //Continue sending messages to the WoodenFrame and
    // Canvas objects asking them to report on some aspect
    // of their state.  Display the information so obtained
    // for the benefit of the user.
    System.out.println("Total length of canvas:" 
      + canvas.getTotalLength() + " inches");
    System.out.println(
      "Total width of canvas: " 
                  + canvas.getTotalWidth() + " inches");
    System.out.println("Total cost of wood is: " 
                        + woodenFrame.getTotalCost());
    System.out.println("Total cost of canvas: " 
       + canvas.getTotalCost() + " dollars");
                     
    //Here, the painting object sends a message to itself
    // asking itself to report on the total material cost.
    // This message causes a method  to be invoked which
    // sends messages to the WoodenFrame and Canvas 
    // objects asking them to report on their individual
    // total costs.  The method returns the sum of the 
    // individual costs as the total cost for the project.
    // The total cost is displayed for the benefit of
    // the user.
    System.out.println("Total cost: " 
               + this.getTotalMaterialCost() + " dollars");
  }//end showOutput()
  //-----------------------------------------------------//

  private double getTotalMaterialCost(){
    //Send messages to the WoodenFrame and Canvas objects
    // asking them to return their total costs.  Add these
    // individual costs and return them as the total 
    // material cost for the project.
    return (canvas.getTotalCost() 
                            + woodenFrame.getTotalCost());
  }//end getTotalMaterialCost()
  //-----------------------------------------------------//
}//end class Ood03
//=======================================================//

class Canvas{
  //This class represents the material used to cover the
  // wooden frame for a painting.  It has length, width,
  // cost-per-square-foot, and binding margin attributes.
  // Each of these is represented by an instance
  // variable.
  //It uses mutator methods to set the values of the
  // instance variables.
  //It does not provide field accessors by which the
  // values of the instance variables can be read.  
  // However, it knows how to calculate the total material
  // cost for one instance of itself, and provides 
  // accessors by which higher-level representations of 
  // the instance variables can be obtained: total length,
  // total width, and total cost.
  
  //Instance variables
  private final double margin = 5.0;
  private double length; //length of the painting
  private double width; //width of the painting
  private double costPerSqFt; //cost of the canvas  
  //-----------------------------------------------------//
  
  //Mutator Methods
  //-----------------------------------------------------//
  
  public void setLength(double length){
    this.length = length;
  }//end setLength()
  //-----------------------------------------------------//
  
  public void setWidth(double width){
    this.width = width;
  }//end setWidth()
  //-----------------------------------------------------//
  
  public void setCostPerSqFt(double costPerSqFt){
    this.costPerSqFt = costPerSqFt;
  }//end setCostPerSqFt()
  //-----------------------------------------------------//
  
  //Accessor Methods
  //-----------------------------------------------------//
  
  public double getTotalLength(){
    //Total length is the length of the painting plus
    // the binding margin required to fold the canvas
    // under the frame and staple it.
    return (length + margin);
  }//end getTotalLength()
  //-----------------------------------------------------//

  //Total width is as described above.  
  public double getTotalWidth(){
    return (width + margin);
  }//end getTotalWidth()
  //-----------------------------------------------------//
  
  public double getTotalCost(){
    return (
     (((length+margin) * (width+margin))*costPerSqFt)/144);
  }//end getTotalCost()
  //-----------------------------------------------------//
}//end class Canvas
//=======================================================//

class WoodenFrame{
  //This class represents the wooden frame that is covered
  // with canvas for a painting.  It has length, width,
  // and cost-per-inch attributes which are stored in
  // instance variables.
  //It uses mutator methods to set the values of the
  // instance variables.
  //It does not provide field accessors by which the
  // values of the instance variables can be read.  
  // However, it knows how to calculate the total material
  // cost for one instance of itself, and provides 
  // accessors by which higher-level representations of 
  // the instance variables can be obtained: total length
  // of wood required and total cost.
  
  //Instance variables
  private double length; //of the painting  
  private double width; //of the painting
  private double costPerInch; //for the wood
  //-----------------------------------------------------//
  
  //Mutator Methods
  //-----------------------------------------------------//
  
  public void setLength(double length){
    this.length = length;
  }//end setLength()
  //-----------------------------------------------------//
  
  public void setWidth(double width){
    this.width = width;
  }//end setWidth()
  //-----------------------------------------------------//
  
  public void setCostPerInch(double costPerInch){
    this.costPerInch = costPerInch;
  }//end setCostPerInch()
  //-----------------------------------------------------//

  //Accessor Methods
  //-----------------------------------------------------//
  
  public double getTotalLengthToBuy(){
    //The total length of the wood required to build the
    // frame is twice the sum of the length and the width
    // of the painting.
    return (2*(length + width));
  }//end getTotalLengthToBuy()
  //-----------------------------------------------------//
  
  public double getTotalCost(){
    //The total cost of the wood is the product of the
    // total length of the wood in inches and the cost
    // per inch.
    return ((2*(length + width))*costPerInch);
  }//end getTotalCost()
  //-----------------------------------------------------//
}//end class WoodenFrame
//=======================================================//

//Note this is a general purpose class that is used to 
// service input from the keyboard and was not designed
// for this specific program.  Rather, it was taken, with
// permission by the author, from the book listed below.

// Simple input from the keyboard for all primitive types.
 // Copyright (c) Peter van der Linden,  May 5 1997.
 // Feel free to use this in your programs, as long as this
 // comment stays intact.
 //
 // This is not thread safe, not high performance, and 
 // doesn't service EOF.
 // It's intended for low-volume easy keyboard input.
 // An example of use is:
 //     EasyIn easy = new EasyIn();
 //     int i = easy.readInt();   
 // reads an int from System.in
 // See Just Java and Beyond, Third Edition by Peter
 // van der Linden

class EasyIn {    
  static InputStreamReader is = 
                        new InputStreamReader( System.in );
  static BufferedReader br = new BufferedReader( is );
  StringTokenizer st;

  StringTokenizer getToken() throws IOException {
    String s = br.readLine();
    return new StringTokenizer(s);
  }//end getToken()
     
  boolean readBoolean() {
    try {
      st = getToken();
      return new Boolean(st.nextToken()).booleanValue();
    }catch (IOException ioe) {
      System.err.println(
                    "IO Exception in EasyIn.readBoolean");
      return false;
    }//end catch
  }//end readBoolean()

  byte readByte(){
    try {
      st = getToken();
      return Byte.parseByte(st.nextToken());
    }catch (IOException ioe) {
      System.err.println(
                       "IO Exception in EasyIn.readByte");
      return 0;
    }//end catch
  }//end readByte()

  short readShort(){
    try {
      st = getToken();
      return Short.parseShort(st.nextToken());
    }catch (IOException ioe) {
      System.err.println(
                      "IO Exception in EasyIn.readShort");
      return 0;
    }//end catch
  }//end readShort()
     
  int readInt(){
    try {
      st = getToken();
      return Integer.parseInt(st.nextToken());
    }catch (IOException ioe) {
      System.err.println(
                        "IO Exception in EasyIn.readInt");
      return 0;
    }//end catch
  }//end readInt()

  long readLong(){
    try {
      st = getToken();
      return Long.parseLong(st.nextToken());
    }catch (IOException ioe) {
      System.err.println(
                      "IO Exception in EasyIn.readFloat");
      return 0L;
    }//end catch
  }//end readLong()

  float readFloat() {
    try {
      st = getToken();
      return new Float(st.nextToken()).floatValue();
    }catch (IOException ioe) {
      System.err.println(
                      "IO Exception in EasyIn.readFloat");
      return 0.0F;
    }//end catch
  }//end readFloat()

  double readDouble() {
    try {
      st = getToken();
      return new Double(st.nextToken()).doubleValue();
    }catch (IOException ioe) {
      System.err.println(
                     "IO Exception in EasyIn.readDouble");
      return 0.0;
    }//end catch
  }//end readDouble()

  char readChar() {
    try {
      String s = br.readLine();
      return s.charAt(0);
    }catch (IOException ioe) {
      System.err.println(
                       "IO Exception in EasyIn.readChar");
      return 0;
    }//end catch
  }//end readChar()

  String readString() {
    try {
      return br.readLine();
    }catch (IOException ioe) {
      System.err.println(
                     "IO Exception in EasyIn.readString");
      return "";
    }//end catch
  }//end readString
}//end class definition
//=======================================================//

-end-