Fundamentals of Computer Science II (CSC-152 99S)


Notes on Exam 1: Java Fundamentals

This page may be found online at http://www.math.grin.edu/~rebelsky/Courses/CS152/98S/Handouts/examsoln.01.html.

Problems

1. Recompilation

Carla and Carl Caffeinated, two of your fellow students, have been working on a new assignment for CS152. They've decided that they need a main class, which they call Main, and a utility class for the stuff that their program manipulates, which they call, surprisingly enough, Stuff.

As you might guess, the main method of Main creates a number of Stuff objects and calls some of the methods those objects provide.

Because they are novice programmers, they've been finding that they need to make many changes to Stuff. They've noted that some of the time they recompile Stuff, they also need to recompile Main for the changes to take effect, but other times they don't need to. Because they're working on the joyfully slow HPs in the MathLAN, they'd prefer to avoid recompilation whenever possible.

Write a short summary of when Carl and Carla will and will not need to recompile Main after recompiling Stuff. Your answer cannot be ``they should recompile Main if the changes seem to have no effect''. Rather, your answer should be sufficiently clear that they could decide what to do, even if there are no immediately observable effects of the change.

A number of you asked me whether they changed Main at all. The answer is no.

Most of you neglected to consider the addition of new methods to the class (which is important if you overload method names). I was somewhat more lenient than I would normally be for such problems.

A few of you seemed to miss the point of information hiding, and indicated that internal changes to Stuff would require recompilation of Main. For example, some suggested that if you changed the names of fields in Stuff, you'd need to recompile Main, when the whole point of information hiding is that Main doesn't know anything about the fields of Stuff.

If Carl and Carla do not add or delete any methods or constructors in Stuff and do not change the signatures of any methods or constructors, and do not change the protection-level of anything in the class, they do not need to recompile Main.

All of those changes take advantage of (1) information hiding and (2) dynamic loading. Information hiding says that if you do not change the way in which the class presents itself to the outside world, it does not matter what you change ``behind the scenes'' as it were. Dynamic loading says that a class is only incorporated when a program that uses it is executed. (In some languages, the code of a class is incorporated when the program that uses it is compiled.)

Note that you cannot say ``you need not recompile Main if none of the signatures of the methods or constructors that Main uses change''. Why not? Suppose that coercion were involved in the choice of which method in Stuff to call (e.g., our old average example, in which a call with two integers used an average method which took two doubles as parameters). Then the addition of a new method closer to the types of the actual calls would not be used unless Main were recompiled.

Hence, if Carl and Carla add any methods or constructors with type signatures that are closer to the actual calls in Main, then they must recompile Main. (For safety's sake, they should recompile Main if they add any new methods or constructors to Stuff with the same names as existing methods in Stuff).

Considering the same issue from the opposite direction, if Carl and Carla delete any methods used by Main, they need to recompile Main.

Similarly, if Carl and Carla change the signatures or return values of any methods or constructors used by Main, they will need to recompile Main. If Carl and Carla only change the bodies of methods or constructors (without changing the signatures of these methods or constructors), then they will not need to recompile Main.

2. Polymorphism

There are a number of ways in which computer scientists define polymorphism. See how many you can find. Are they all essentially equivalent, or are there substantial differences between the different definitions?

I had indicated that two definitions (other than my own) would be sufficient. Most of you found at least two. A few of you neglected to cite the definitions you wrote, usually with the result of a severe penalty. A few of you didn't write any definitions (just reported on your findings). I felt that it was implied by the problem, but did not penalize you severely.

Note that when you're citing web resources, you need to give the full URL, the date you accessed the page, and the date the page was modified.

A few of you said ``Yup, they're all the same'' when a casual observer would have seen no similarities (``one refers to pointers, another to interfaces, and a third to subclassing, how do they relate?'').

Here are some of the online sites you found (I also appreciated those of you who referred to real books).

3. Fractions

Fillip and Fiona Fictitious are fooling with the Fraction class that you used for assignment 4. They've had a number of problems, and would like your help.

3.a. Addition

Fillip has been testing the addition method, and getting what he thinks are incorrect results. Here's the main method he's been using.

  /** Compute 1/3 + 2/7. */
  public static void main(String[] args) {
    SimpleOutput out = new SimpleOutput();
    Fraction frac = new Fraction(1,3);
    frac.add(new Fraction(2,7));
    out.println(frac.toString());
  } // main(String[])

For some reason, his output is always 1/3. Explain why Fillip's results are ``incorrect''.

The add method does not update the current fraction. Rather, it creates a new fraction. Hence, the call to

    frac.add(new Fraction(2,7));

basically says ``add 2/7 to frac and then throw away the result''. It is little different from

    int i = 2;
    i + 4;

Now, one might ask why Java permits this, but that's a topic for another day, or another exam.

3.b. Conversion

Fiona has noted that there are times when she has been using Fractions when she really needs real numbers. She's decided to write an FloatFraction class that extends the Fraction class to add a toFloat method which returns the float equivalent of the current fraction. For example, given the fraction 1/2, toFloat would return 0.5.

Here's what she's written so far.

import Fraction;
/**
 * Fractions that can be converted to real numbers.
 *
 * The original Fraction class is by our beloved professor, Samuel
 * A. Rebelsky.  We used version 1.0 of February 1999.
 *
 * The idea to make this modification came from a collaboration
 * with the Caffeinateds.
 *
 * @author Fiona Fictitious
 * @author Fillip Fictitious
 * @version 0.0 of February 1999
 */
public class FloatFraction
  extends Fraction {
  /** Convert the current fraction to a float. */
  public float toFloat() {
    // Help!
    return 0;
  } // toFloat()
} // class FloatFraction

Help Fiona finish her function. That is, fill in the body of toFloat. (You should remove the line that returns 0; Fiona just put it there as a stub.)

Basically, we need to divide the numerator by the denominator. However, since both are longs, Java will do ``integer division'', rounding to the nearest ``smaller'' integer value. Since we want it to do real division, we must tell it to convert both numerator and denominators to floats before division.

Since FloatFraction is a subclass of Fraction, it has access to the fields of Fraction. This makes accessing and modifying those fields relatively easy.

Of course, in order to use this class, we'll need to add constructors (not required for this question, but important if you were doing testing). I've done that in this example.


import Fraction;
/**
 * Fractions that can be converted to real numbers.
 *
 * The original Fraction class is by our beloved professor, Samuel
 * A. Rebelsky.  We used version 1.0 of February 1999.
 *
 * The idea to make this modification came from a collaboration
 * with the Caffeinateds.
 *
 * @author Fiona Fictitious
 * @author Fillip Fictitious
 * @author Clif Flynt
 * @author Samuel A. Rebelsky
 * @version 1.0 of March 1999
 */
public class FloatFraction
  extends Fraction {
  
  // +--------------+---------------------------------------------
  // | Constructors |
  // +--------------+
  
  /** Build a new fraction with both numerator and denominator. */
  public FloatFraction(long num, long denom) {
    super(num,denom);
  } // FloatFraction(long,long)
  
  /** Build a new fraction that corresponds to a particular integer. */
  public FloatFraction(long val) {
    super(val);
  } // FloatFraction(long)
  
  /** Build a new fraction. */
  public FloatFraction() {
    super();
  } // FloatFraction()
  
  // +---------+--------------------------------------------------
  // | Methods |
  // +---------+
  
  /** Convert the current fraction to a float. */
  public float toFloat() {
    // Convert to floats and then divide
    return ((float) this.num) / ((float) this.denom);
  } // toFloat()
} // class FloatFraction


Now we might want to test this new class. Here's a class for doing that testing. It takes numerator and denominator from the command line.


import FloatFraction;
import SimpleOutput;
/**
 * Test the FloatFraction class.
 * Usage:
 *   % java TestFloatFraction
 *     Build the default fraction and print it out in both forms.
 *   % java TestFloatFraction val
 *     Build the fraction val/1 and print it out in both forms.
 *   % java TestFloatFraction num denom
 *     Build the fraction num/denom and print it out in both forms.
 */
public class TestFloatFraction {
  /** Test away! */
  public static void main(String[] args) throws Exception {
    // Prepare for output.
    SimpleOutput out = new SimpleOutput();
    // The fraction we're creating.
    FloatFraction ff;
    // Zeroary constructor
    if (args.length == 0) 
      ff = new FloatFraction();
    // Unary constructor
    else if (args.length == 1)
      ff = new FloatFraction(Long.parseLong(args[0]));
    // Binary constructor
    else
      ff = new FloatFraction(Long.parseLong(args[0]),
                             Long.parseLong(args[1]));
    // Print appropriate information                        
    out.println(ff.toString() + " = " + ff.toFloat());
  } // main(String[])
} // class TestFloatFraction


And here are the tests. The particular criteria are left to your imagination. Note that I'm using the non-simplifying Fraction class.

% java TestFloatFraction
0 = 0.0
% java TestFloatFraction 1
1 = 1.0
% java TestFloatFraction 51
51 = 51.0
% java TestFloatFraction -1
-1 = -1.0
% java TestFloatFraction 999999999999999999999
java.lang.NumberFormatException: 999999999999999999999
        at java.lang.Long.parseLong(Long.java)
        at java.lang.Long.parseLong(Long.java)
        at TestFloatFraction.main(TestFloatFraction.java:25)
% java TestFloatFraction 0
0 = 0.0
% java TestFloatFraction 1 2
1/2 = 0.5
% java TestFloatFraction 2 7
2/7 = 0.2857143
% java TestFloatFraction 100 10
100/10 = 10.0
% java TestFloatFraction 10 1000
10/1000 = 0.01
% java TestFloatFraction -1 5
-1/5 = -0.2
% java TestFloatFraction 1 -5
1/-5 = -0.2
% java TestFloatFraction 1 5
1/5 = 0.2
% java TestFloatFraction -1 -5
-1/-5 = 0.2

3.c. Conversion, Revisited

Fillip has suggested that in addition to the toFloat method, they need a method that adds another fraction to the current fraction and returns a float. Here's what he's come up with.

  /** 
   * Add another fraction to the current fraction, returning
   * the result as a float.
   */
  public float add(Fraction another) {
    // Help!
    return 0;
  } // add(Fraction)

i. Help Fillip finish his function. That is, fill in the body of add. (You should remove the line that returns 0; Fillip just put it there as a stub.)

It would be tempting to add the two using the add method from the Fraction class and then use toFloat. However, the result of such addition is a Fraction (rather than a FloatFraction), and Fractions don't have a toFloat method. Hence, we'll just convert both fractions by hand, and then add the results. (You could also build the new fraction by hand, and then convert as above.)

  /** 
   * Add another fraction to the current fraction, returning
   * the result as a float.
   */
  public float add(Fraction another) {
    return (((float) this.num) / ((float) this.denom)) +
           (((float) other.num) * ((float) other.denom));
  } // add(Fraction)

ii. Java will complain if Fillip tries to add your improved function to the FloatFraction class. Why?

There is already another method in the Fraction class with signature add(Fraction). You cannot override that method unless you give it the same return type. Why not? Well, polymorphism says that ta FloatFraction can be used anywhere a Fraction can be used. But if we call the add(Fraction) method of a Fraction, we get a Fraction back, so we could assign it to another Fraction or use it in another call to add. However, this new method says ``when you call add, you get back a float'' and, as far as Java knows, you can't do the same things with floats that you can do with Fractions.

4. Analyzing Area

Andy and Andrea Analyst have been working with a number of problems that have to do with area. Among other things, they've decided that they'll need to add areas. They've also learned that their analyses are aided by illustrations of areas. Hence, they also have decided to draw areas. Some of the times, they want to draw areas as circles, other times they want to draw them as squares.

Putting all of their thoughts together, they've come up with five classes or interfaces they want to build.

4.a. Design

Because Java only permits a class to extend one other class, they cannot make all of these classes. Which should be interfaces, and why?

This was somewhat of an open-ended question, at least at the top-level. It is not immediately clear whether DrawableThing or AddableThing is better suited to ``class-hood'' or ``interface-hood''. This part of the problem was worth 10 points.

One question I use for deciding what should be a class and what should be an interface is ``does it have a reasonable default behavior?''. Arguably, neither DrawableThing nor AddableThing have a reasonable default behavior, so I'll make both of them interfaces. (You may have decided something else.)

Area is clearly a class. We know how to add areas and can choose some default way of drawing areas (such as ovals or circles). Area therefore implements both DrawableThing and AddableThing.

Since CircularArea and SquareArea are both Areas, and Area is a class, both CircularArea and SquareArea must be classes.

From another perspective, we may want to say ``whenever you create a drawable object, you must specify its base color and center''. If we make that design decision, it makes sense to make DrawableThing a class, since we'll want to give it an appopriate constructor.

4.b. Implementation

Using these specifications, build the five classes or interfaces.

As I suggested in the policies and in class, I wasn't looking for working code (although working code is always nice). I did, however, want to see enough to verify that you'd be able to do it given more time.

Hopefully, the following classes and interfaces will be self-evident. I did note that while I can add any two areas together, it's not clear that I can add any other addable thing to an area. Hence, the add method can throw an exception if it doesn't know how to add that thing. Note that I've also changed the specifications slightly so that the draw method takes the center as a parameter. I've also added a number of useful methods to Area. You were not required to include all of these methods (in fact, all you really needed were a constructor and the two core methods). Finally, note that there is very little to the last two classes, since they can rely on Area to provide most of the functionality. They just need to include appopriate constructors and override the draw method.

Here is some rough code. It does not yet work correctly.

DrawableThing.java


import java.awt.Graphics;

/**
 * Things that you can draw.    Created as part of the answer key for an 
 * exam in CS152 99S.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of March 1999
 */
public interface DrawableThing {
  /**
   * Draw this thing in the current color (or other appropriate color
   * or colors), centered at the given position.
   */
  public void draw(Graphics g, int x, int y);
} // interface DrawableThing


AddableThing.java


/**
 * Things you can usually add to each other.  Created as part of the answer key 
 * for an exam in CS152 99S.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of March 1999
 */
public interface AddableThing {
  /**
   * Add something else to the current thing.  Since we don't know how
   * to add all addable things to one-another (e.g., does it make sense
   * to add areas and fractions?), this can also throw an exception.
   *
   * @exception Exception
   *   When the parameter is not something we know how to add to the
   *   current thing.
   */
  public AddableThing add(AddableThing other) throws Exception;
} // interface AddableThing


Area.java


import java.awt.Graphics;
import AddableThing;
import DrawableThing;

/**
 * Areas that you can visualize.  Created as part of the answer key for an
 * exam in CS152 99S.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of March 1999
 */
public class Area
  implements AddableThing, DrawableThing
{
  // +--------+---------------------------------------------------
  // | Fields |
  // +--------+
  
  /** The size of the area, represented as a number. */
  protected double size;
  
  // +--------------+---------------------------------------------
  // | Constructors |
  // +--------------+
  
  /** Create a new area of specified size. */
  public Area(double size) {
    this.size = size;
    if (this.size < 0.0) this.size = 0;
  } // Area(double)
  
  // +---------+--------------------------------------------------
  // | Methods |
  // +---------+
  
  /** Get the size of the curent area. */
  public double getSize() {
    return this.size;
  } // getSize()
  
  /** Increase the size of the current area by a specified amount. */
  public void enlarge(double amount) {
    this.size += amount;
    if (this.size < 0.0) this.size = 0.0;
  } // enlarge(double)
  
  /** Decrease the size of the current area by a specified amount. */
  public void shrink(double amount) {
    this.size -= amount;
    if (this.size < 0.0) this.size = 0.0;
  } // shrink(double)
  
  /** Scale the size of the current area by a specified amount. */
  public void scale(double factor) {
    this.size *= factor;
    if (this.size < 0.0) this.size = 0.0;
  } // scale(double)
  
  /** Add another area to the current one, creating a new area. */
  public Area add(Area other) {
    return new Area(this.size + other.size);
  } // add(Area)
  
  /** Add something else addable to the current area, if possible. */
  public AddableThing add(AddableThing other)
    throws Exception
  {
    if (other instanceof Area) return add((Area) other);
    else throw new Exception("Can't add apples and oranges");
  } // add(AddableThing)
  
  /**
   * Draw an approximate representation of this area, in the current color, 
   * centered at a particular point. Doesn't do very well with areas that
   * are hard to represent as whole numbers or small areas. */
  public void draw(Graphics g, int x, int y) {
    // Drawing it as a square (or near-square) is probably the easiest thing.
    // We'll compute the width as the square root of the area, round down,
    // and then compute the height.  This will make something like 15 have
    // the correct size.  (If we just used sqrt(15), we'd get something a little
    // bit less than 4, round down to 3, and end up with a 3x3 area.)
    int height = (int) Math.sqrt(this.size);
    int width = (int) (this.size / height);
    // Okay, ready to draw
    g.fillRect(x-width/2, y-height/2, width, height);
  } // draw(Graphics, int, int)
} // class Area


CircularArea.java


import java.awt.Graphics;
import Area;

/**
 * Areas that we draw as circles.  Created as an example for an exam answer
 * key for CSC152 99S at Grinnell College.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of February 1999
 */
public class CircularArea 
  extends Area
{
  // +--------------+---------------------------------------------
  // | Constructors |
  // +--------------+
  
  /** Create a new area of specified size. */
  public CircularArea(double size) {
    super(size);
  } // CircularArea(double)
  
  // +---------+--------------------------------------------------
  // | Methods |
  // +---------+

  /**
   * Draw the area as a circle, using the current color, centered at
   * the specified point.  If it's not possible to center, may be offset
   * slightly.  If it's not possible to represent the area accurately
   * (and it's probably not), gives an approximation.
   */
  public void draw(Graphics g, int x, int y) {
    // If area = pi*r*r, we know that r*r = area/pi, and r = sqrt(area/pi).
    // Java rounds down.  We'd rather it round towards the "nearest" number
    // (rounding up if over .5, down if under .5.  We can get it to do this
    // kind of rounding by adding .5 before converting to a number (think
    // about it).  It might be better to be a little bit more careful, but
    // this is good enough for our first experiments.
    int radius = (int) (Math.sqrt(size/Math.PI) + 0.5);
    // Draw away!
    g.fillOval(x-radius, y-radius, 2*radius, 2*radius);
  } // draw(Graphics, int, int)
} // class CircularArea


SquareArea.java


import java.awt.Graphics;
import Area;

/**
 * Areas that we draw as circles.  Created as an example for an exam answer
 * key for CSC152 99S at Grinnell College.
 *
 * @author Samuel A. Rebelsky
 * @version 1.0 of February 1999
 */
public class SquareArea 
  extends Area
{
  // +--------------+---------------------------------------------
  // | Constructors |
  // +--------------+
  
  /** Create a new area of specified size. */
  public SquareArea(double size) {
    super(size);
  } // SquareArea(double)
  
  // +---------+--------------------------------------------------
  // | Methods |
  // +---------+

  /**
   * Draw the area as a circle, using the current color, centered at
   * the specified point.  If it's not possible to center, may be offset
   * slightly.  If it's not possible to represent the area accurately
   * (and it's probably not), gives an approximation.
   */
  public void draw(Graphics g, int x, int y) {
    // If area = side*side, then side = sqrt(area).
    // Java rounds down.  We'd rather it round towards the "nearest" number
    // (rounding up if over .5, down if under .5.  We can get it to do this
    // kind of rounding by adding .5 before converting to a number (think
    // about it).  It might be better to be a little bit more careful, but
    // this is good enough for our first experiments.
    int side = (int) (Math.sqrt(size) + 0.5);
    // Draw away!
    g.fillRect(x-side/2, y-side/2, side, side);
  } // draw(Graphics, int, int)
} // class SquareArea


AreaTester.java


import SquareArea;
import CircularArea;
import Area;
import java.awt.*;
import java.applet.*;

/**
 * A very simple applet that test the drawing of areas (and not their
 * dozens of other features).  Created as an example for an answer key
 * for the first exam in Grinnell's CSC152 99S.
 *
 * By setting appropriate parameters (kind=plain,circle,square; size=N),
 * you can perform your various tests.
 */
public class AreaTester
  extends Applet
{
  public void paint(Graphics g) {
    double size = 15; // An interesting default.
    Area a = new Area(size);  // A less interesting default.
    // Get the size.
    try { (new Double(getParameter("Size"))).doubleValue(); }
    catch (Exception e) { 
      g.setColor(Color.red);
      g.drawString("Cannot parse " + getParameter("Size"), 0, 10);
      return;
    }
    // Determine the kind.
    if (getParameter("Kind").equals("plain")) a = new Area(size);
    else if (getParameter("Kind").equals("circle")) a = new CircularArea(size);
    else if (getParameter("Kind").equals("square")) a = new SquareArea(size);
    else {
      g.setColor(Color.red);
      g.drawString("Only plain, circle, and square are permitted.",0,10);
    }
    // Draw away
    g.setColor(Color.blue);
    a.draw(g,50,50);
  } // paint(Graphics)
} // class AreaTester


5. Inventories

Irma and Irving have hired your to work on their object-oriented inventory system. They have given you the following specification.

Construct a class we can use to track the inventory of individual products. This class will be used to build an inventory control system.

The class should have fields for a name for the product, an id number (so that we can distinguish products with similar names), retail cost, wholesale cost, and quantity on hand.

They think that you're smart enough to decide which methods you'll need. When you press them, they say ``You'll need methods to report the value of the inventory at retail cost, remove a quantity from the inventory (when things are sold), and other stuff like that.'' It does seem like you'll need to decide on the methods yourself.

Build this class and develop an appropriate test plan. You need not implement the test plan, simply describe it.

Once again, it is hoped that the code is self-explanatory. No tester this time. You should note that I've used longs for the costs. Why? Because I worry about precision. This does mean that everything needs to be expressed in cents. I don't really worry about overflow, since I'm not handling the U.S. debt. I've also been clever in adding a profit field. You need not have included such a field. You were also not required to fill in the details, although I have done so for this example.


/**
 * Inventory one particular type of product.  Created as part of the
 * answer key for exam 1 in Grinnell's CSC152 99S.  Note that all 
 * costs must be represented as whole numbers.  You can think of these
 * as "cents" or whatever currency you think is most appropriate, as
 * long as it has no fractional part.  For example, if prices could be
 * $1.50, then dollars is not an appropriate base.  However, the toString
 * method assumes that the base value is, in fact, pennies.
 *
 * @author Samuel A. Rebelsky
 * @author Clif Flynt
 * @version 1.0 of February 1999
 */
public class ProductInventory {

  // +--------+---------------------------------------------------
  // | Fields |
  // +--------+

  /** The name of the product. */
  protected String name;
  
  /** The ID number of the product. Used a string to permit things like
   *  111-XXY */
  protected String id;
  
  /** The retail cost of the product. */
  protected int retail;
  
  /** The wholesale cost of the product. */
  protected int wholesale;
  
  /** The number of items in stock. */
  protected int stock;
  
  /** A historical record of our profit on this item. */
  protected int profit;
  
  // +--------------+---------------------------------------------
  // | Constructors |
  // +--------------+

  /** 
   * Create an inventory for a new item.  You must specify name, id,
   * wholesale cost, and retail cost.  It is assumed that we begin with
   * zero of any item.  As described in the introduction, all costs must
   * be whole numbers.  Permits "unreasable" (i.e., negative) prices.
   */
  public ProductInventory(String name, String id, int retail, int wholesale) {
    this.name = name;
    this.id = id;
    this.retail = retail;
    this.wholesale = wholesale;
    this.stock = 0;
    this.profit = 0;
  } // ProductInventory(name,id,retail,wholesale)
  
  // +------------------+------------------------------------------
  // | Standard Methods |
  // +------------------+
  
  /**
   * Determine if another inventory is for the same product.
   */
  public boolean equals(ProductInventory other) {
    return this.id.equals(other.id);
  } // equals(ProductInventory)
  
  /**
   * Determine if another object is inventory for the same product.
   */
  public boolean equals(Object other) {
    return (other instanceof ProductInventory) &&
           this.equals((ProductInventory) other);
  } // equals(Object)
  
  /**
   * Convert to a string for easy printing.
   */
  public String toString() {
    return this.id + "[" + this.name + "] " +
           this.stock + " in stock at " +
           "$" + (this.wholesale / 100) + "." + (this.wholesale % 100) +
           " wholesale and " +
           "$" + (this.retail / 100) + "." + (this.retail % 100) +
           "retail";
  } // toString()
  
  // +---------+--------------------------------------------------
  // | Methods |
  // +---------+

  /** 
   * Acquire more of this product at the standard wholesale price. 
   * Pre: Does not overflow the stock bins (the total stock is not more
   *   than Long.MAX_VALUE)
   * Pre: We acquire a nonnegative amount of stock.
   * Post: The stock is updated.
   * Post: The profit is reduced appropriately.
   */
  public void acquire(int amount) {
    this.stock += amount;
    this.profit -= amount*this.wholesale;
  } // acquire(int)
  
  /**
   * Acquire more of this product at a "sale" price (one other than
   * the standard wholesale price).  See above for preconditions and
   * postconditions.
   */
  public void acquire(int amount, int price) {
    this.stock += amount;
    this.profit -= amount*price;
  } // acquire(int,int)
  
  /**
   * Determine our profit (or loss) to date on this product.  Does
   * not take the potential profit from current stock into account
   * (that is, calculates profit as if any stock we have on hands is
   * a total loss).
   */
  public int getProfit() {
    return this.profit;
  } // getProfit()
  
  /**
   * Get the cost to replace this product, if we had a fire or other
   * damage.
   */
  public int getReplacement() {
    return this.stock * this.wholesale;
  } // getReplacment()
  
  /**
   * Determine the current retail price.
   */
  public int getRetail() {
    return this.retail;
  } // getRetail()
  
  /**
   * Determine the amount of stock we have on hand.
   */
  public int getStock() {
    return this.stock;
  } // getStock()
  
  /**
   * Get the value of the inventory (at retail).
   */
  public int getValue() {
    return this.stock * this.retail;
  } // getValue()
  
  /**
   * Get the current wholesale price.
   */
  public int getWholesale() {
    return this.wholesale;
  } // getWholesale
  
  /**
   * Sell some of this product at the standard wholesale price.
   * Pre: The amount sold is nonnegative.
   * Pre: The amount sold is no more than stock on hand.
   * Post: The stock is depleted.
   * Post: The profit increases appropriately.
   */
  public void sell(int amount) {
    this.stock -= amount;
    this.profit += amount*this.wholesale;
  } // sell(int)
  
  /**
   * Sell some of the product at a special price.  See above for
   * preconditions and postconditions.
   */
  public void sell(int amount, int price) {
    this.stock -= amount;
    this.profit += amount*price;
  } // sell(int,int)
  
  /**
   * Set wholesale and retail prices (it's best to do both together,
   * because when your wholesale price changes, you'll want to update
   * your retail price). 
   */
  public void set(int wholesale, int retail) {
    this.wholesale = wholesale;
    this.retail = retail;
  } // set(int,int)

  /**
   * Once in a while you just want to set the retail price.
   */
  public void set(int retail) {
    this.retail = retail;
  } // set(int)
} // class ProductInventory



History


Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.

This page may be found at http://www.math.grin.edu/~rebelsky/Courses/CS152/99S/Handouts/examsoln.01.html

Source text last modified Mon Mar 8 10:45:17 1999.

This page generated on Mon Mar 8 15:19:38 1999 by SiteWeaver. Validate this page's HTML.

Contact our webmaster at rebelsky@math.grin.edu