NetBeans project

The produce tracking problem

You have been hired by the Acme Produce Warehouse to write a simple application to keep track of their stock of fruits and vegetables. At the start of each day, the office gets a report of how many cases of various items of produce are currently in stock. During each business day trucks arrive bringing fresh produce and trucks leave carrying produce to customers. Each time a truck arrives or leaves, the office gets a report of how many cases of each kind of produce have come in or gone out on that particular truck. Given all of this information, the office can determine how many cases of produce should be in stock at the end of the day.

You have been asked to write a program that will automatically compute stock levels at the end of the day. The program will run once per day after all information about cases arriving and departing for the day has been gathered. Your program will read all of the information it needs from a text file named "stock.txt" that contains information about how much produce was in stock at the start of the day and how many cases of each kind of produce arrived and left during the day. Here is what a typical stock.txt file looks like:

stock apples 52
stock lettuce 24
stock oranges 12
stock tomatoes 14
stock onions 25
stock broccoli 36
stock potatoes 20
out oranges 10
out apples 10
out broccoli 10
in onions 50
out potatoes 12
out tomatoes 8
in tomatoes 20

Each line starts with a word that tells you whether this line is reporting a stock level from the start of the day, a shipment going out, or a shipment coming in. The second item on each line identifies the variety of produce in question, and the third item is an integer count of a number of cases. In writing your program you should make no assumptions about what kinds of produce are stocked at the warehouse, as that may change over time. For example, grapes do not appear on the list above because grapes are a seasonal item that are stocked only at certain times in the year.

Your job is to write a program that will read the information from the stock.txt file and use it to construct and print a stock report at the end of the day. For example, given the information in the file above your program should print

apples 42
lettuce 24
oranges 2
tomatoes 26
onions 75
broccoli 26
potatoes 8

Setting up data structures for the problem

For our solution we will need to create two classes. The first class is a simple class that records stock levels for a single type of produce.

public class Item {
    private String name;
    private int quantity;

    public Item(String name) {
        this.name = name;
        quantity = 0;
    }
}

We will eventually need to add additional methods to this class.

Next, we need a class that can track the warehouse's entire inventory of items.

public class Inventory {
    private ArrayList<Item> stock;

    public Inventory() {
        stock = new ArrayList<Item>();
    }
}

We will also need to add methods to this class - in the section below we will start the process of figuring out which methods we need.

Top-down design

A big part of writing an object-oriented program is deciding what methods we need to add to each of our classes. One very effective strategy for doing this is called top-down design. In this strategy we make a quick sketch of the key classes we will need, and then move to writing the main method for our program. In the course of writing that main method we will discover the need for some of the methods that our classes will require to get the job done.

Here now is the main method for our produce tracker program.

public static void main(String[] args) {
   Scanner input = null;
   try {
       input = new Scanner(new File("stock.txt"));
   } catch(Exception ex) {
       ex.printStackTrace();
       System.exit(0);
   }

   Inventory I = new Inventory();

   while(input.hasNext()) {
    // Read and process one line of input from the file.
    String command = input.next();
    String produce = input.next();
    int cases = input.nextInt();

    if(command.equals("stock")) {
        I.addItems(produce,cases);
    } else if(command.equals("in")) {
        I.addItems(produce,cases);
    } else if(command.equals("out")) {
        I.removeItems(produce,cases);
    }
}
   I.printReport();
}

The main thing driving the action in this method is the structure of the data file that we have to work with. As you can see here, most of the logic in the main method is code that is necessary to read the individual lines in the stock.txt file. Each line in stock.txt is going to cause us to have to either add or remove items from the inventory: this will cause us to add addItems() and removeItems() methods to the Inventory class. Finally, the problem statement says that we need to produce a report after processing the stock.txt file. That report should list all of the items we have in stock along with the quantity of each item. Since the Inventory class has all of the information about items that are in stock, it should take responsibility for printing that report: for that reason we decide to add a printReport() method to that class.

Once we have identified the need for three new methods in the Inventory class we can go to work on writing those methods.

The first method adds a certain number of cases of a given produce item to the inventory. This method will have to figure out whether we already have that item in stock or not. If we do, we just need to find the Item that describes that item and increment its number of cases. If we do not have that item in stock already we will need to create a new Item object and add it to the inventory instead.

public void addItems(String item,int howMany) {
    // When some items come in, we first need to see if those items
    // are already in our stock list
    if(exists(item)) {
        Item existingItem = find(item);
        existingItem.increaseQuantity(howMany);
    } else {
        Item newItem = new Item(item);
        newItem.increaseQuantity(howMany);
        stock.add(newItem);
    }
}

A key question this method needs to answer is whether or not we have the given item in stock already. To help us with that I will add an additional helper method to the Inventory class. The exists() method will take the name of a produce item and determine whether or not we have an Item object in our stock list for that item.

private boolean exists(String name) {
    for(int n = 0;n < stock.size();n++) {
        Item i = stock.get(n);
        if(i.isMyName(name))
            return true;
    }
    return false;
}

Helper methods are typically declared private, since they are for the use of other methods in the class.

addItems() also requires the use of a second helper method, a find() method that can search the stock list for an Item with a given name:

private Item find(String name) {
    for(int n = 0;n < stock.size();n++) {
        Item i = stock.get(n);
        if(i.isMyName(name))
            return i;
    }
    return null;
}

The next method we need to add to the inventory class is removeItems().

public void removeItems(String item,int howMany) {
    Item existingItem = find(item);
    existingItem.decreaseQuantity(howMany);
    if(existingItem.isNoneLeft()) {
        stock.remove(existingItem);
    }
}

This method also gets to take advantage of the find() helper method to quickly find the Item we need to work with.

Finally, here is the code for the printReport() method.

public void printReport() {
    for(int n = 0;n < stock.size();n++) {
        Item i = stock.get(n);
        System.out.println(i);
    }
}

This method makes use of a commonly used technique in Java. If we want to equip a class with the ability to work with the println() or print() methods, we simply have to add a special method to the class: that method is the toString() method, which returns a String that describes the object.

Adding methods to the Item class

In the course of writing the necessary methods for the Inventory class we discovered the need for several new methods in the Item class. Here now is the final version of the Item class with the additional methods needed to get everything working:

public class Item {
    private String name;
    private int quantity;

    public Item(String name) {
        this.name = name;
        quantity = 0;
    }

    public boolean isNoneLeft() {
        if(quantity == 0)
            return true;
        else
            return false;
    }

    public boolean isMyName(String name) {
        if(this.name.equals(name))
            return true;
        else
            return false;
    }

    public void increaseQuantity(int n) {
        quantity += n;
    }

    public void decreaseQuantity(int n) {
        quantity -= n;
    }

    public String toString() {
        return name + ":" + quantity;
    }
}