We want to construct a grocery list program that will allow us to create a grocery list. The list will be created over a period of time and just before a trip to the store the program can print the list. Items will be added to the list ( if you want to order more of an item, you will simply add another list item with the additional order not edit the existing record), and stored in a file between times when you run the program. When the user enters a new item they will enter the number needed and the unit price of the item. The program will print the list (to a window) with the total cost of the items on the list.
First we want to decide on the objects involved in this program. Make a list of the nouns in the paragraph that are associated with the problem.
Not all of these nouns will be modeled in the program, but all things modeled are here (with the exception of interface requirements such as menu). We will delete time period since that is determined by the user. Similarly store is not essential to this problem. The file of items is both an ifstream and an ofstream at different times, but the system provides the functions needed. The number needed and unit price are just numbers belonging to grocery item and total cost is output from the grocery list. This means we will have to create the class GroceryList and the class GroceryItem.
In object oriented design the first thing that we use to characterize a class is the actions it can do. Again we go back to the problem. This time we look for verbs that are connected with the grocery list. We have read from a file, store in a file, add to list, and print. This means that the public view of grocery list will be:
class GroceryList
{
public:
GroceryList();// At least one constructor
void read(istream &); // read from a file
void write(ostream &); // write to the file
void print(); // print the list to the screen
void addItem(); // add an item to the list
private:
// The actual structure of the data storage is not important at this point
};
At first the only obvious functions needed in GroceryItem are read, write and print.
class GroceryItem
{
public:
GroceryItem(); \\ Constructors as needed
void read(istream &);
void write(ostream &);
void print();
};
As we will see, sometimes when we start creating functions we will find that our first guess as to what functions are needed is not always complete. One tool used to show the relationship between classes and to discover additional functions is the Scenario. We will use the GroceryList function print to illustrate our first scenario.
From this scenario we see that we need a function to compute the total cost of the grocery list. The scenario for this function uncovers the need for a function computeCost for GroceryItem. One the other hand there is no need to create a function to print the name of the grocery item, its unit cost, number of items or the total cost since these are all predefined objects (name is a string) or primitives (int or double).
This problem has some aspects we have not encountered before, they are:
Consider the last item first. The library of container classes that all modern c++ compilers has containers for many different purposes. The simplest list is an array class. The Borland array class has some flaws, so we will us my array class. If you have already looked at the file darray.h, you will have noticed that there are four classes defined in the file, TypeRep, Array, ArrayProcess and ArrayIterator. TypeRep is very similar to our counted pointer and is used for memory management. ArrayProcess is used for some fancy work on an array and will be discussed later in the course. We will only use Array and ArrayIterator in this project and for some weeks to come You will also notice some funny notation involving the word template. Templates allow us to define functions for a container once and use them on many different types of objects. Array could be an array of integers or an array of grocery items.
Next week we will worry about coding this problem. For now all we are interest in is the structure of the solution. We can model the problem in two ways, inheritance or containment.
Inheritence | Containment |
One function that wasn't evident from our discussion was a function to clear the list once we used it. We add clearList to the interface and get the following class definitions.
class GroceryList
{
public:
GroceryList();
double computeCost();
void addItem(const GroceryItem &newItem);
void print(ostream &);
void write(ostream &);
void read(istream &);
void clearList();
private:
Array< GroceryItem > _item;
};
and
class GroceryItem
{
public:
GroceryItem();
GroceryItem(string name,string id,double cost, int howMany);
double computeCost();
void print(ostream &);
void write(ostream &);
void read(istream &);
private:
};