cs1ch8sec3.htm
 

CHAPTER 8

AN EVEN BETTER CONTRACT PROGRAM
 


Section III: The List: A Look at Data Representation Section I: Analyzing the Code Implications of an Improved Contract Program Section II:Instances as Array Elements Section IV: Lists: Working with Encapsulation
Section V: Class Declarations for Contract and ListOfContracts Section VI: Member Functions for ListOfContracts Section VII: Improving ListOfContracts Section VIII: Rewriting the Nonmember Functions

  


Table of Contents

Learning C++:
An Index of Entry Points


2. The

of C++

A reference document on the basic elements of C++.



3. The Patterns





Section III. The List: An Initial Look at Data Representation
This program is beginning to look useful. The next step is to allow Olympia to add and delete contracts. One way to do this is to have an area of memory set aside as space for contracts and a way to keep track of how much of that space has been used. We have not needed to keep track of this so far because we have immediately filled all the elements of our arrays.

What we need is a more complex data structure, a structure that not only allows us to store elements as the array does but also includes the new functionality of adding and deleting. Many people call such a structure a list so that is the name we will use. Be aware that what we are about to create here is a specific example of the very general type 'list'. We are bordering on having yet another pattern!

A. A Revised Set of Specifications
First, however, we have changed the problem enough that it is time for a return to specifications. Below is an updated program narrative. You are urged to update the interface analysis developed in chapter 6. Here we will again skip this and focus on discovering the objects and classes. It's again underline the nouns and circle the verbs time:

    Olympia owns a small office cleaning business. She wishes to have a program to keep track of the contracts she has with various businesses. Each contract involves one office complex and should keep track of the square footage of the office, the number of desks in the office, and the number of days per week the office is to be cleaned. A user of this program should be able to change any of this information and get all of it, plus the per week charge which is calculated based on the formula:

      Weekly Charge = Days per Week * ($0.05 per square feet + $5 per desk)

    Users should also be able to add new contracts and delete existing ones. . When adding contracts the contract ID, square footage of the office, the number of desks in the office, and the number of days per week the office is to be cleaned all must be provided. To delete a contract, the user enters the contract ID. No contract can exist that does not have all this information provided initially. Olympia has set a limit on her business of 100 different contracts in order to have time for her family and the other real things of life.

All the changes relevant here are in the second paragraph. First, we can drop the nouns 'family' and 'things of life' since they are really editorial comments. Likewise, the new verb 'provided' has nothing to do with an action of the program. It talks about what the user will do. Don't let such things confuse you.

There are two new verbs that we do need to pay attention to - 'add' and 'delete'. Our earlier analysis discovered one class - contract. Are the add and delete operations performed by a contract? If you think carefully, you will realize that nothing is added to or deleted from the contracts themselves. Rather, contracts are added to or deleted from something else. What is that 'something else' - what object handles the adding and deleting?

The introduction to this section gave away the answer, but it is interesting to note here that the problem narrative only indirectly indicates the need for a new object type, a new class. Something needs to hold all these contracts and allow them to manipulated. That 'something' is a list. Thus, in a bit, we will design a new class that we might call 'ListOfContracts'. This class will be special because in this program we will only have one instance of this class.

Whenever you have a problem that involves grouping together a collection of items, consider the possibility of creating a new class, one of whose properties is the collection itself. We could actually have created a new class to hold the contracts in the last few chapters. We didn't because the built-in C++ type 'array' met our needs quite well and there was no special functionality to be attached to this array type. As we shall see, a list is more complex than simply an array and does have extra functionality.

Let's start, however, by trying to create the list type using only an array:

    typedef
      Contract ListOfContracts[MAX_CONTRACTS];

    ListOfContracts contracts;

As we have designed the constructor for the class 'Contract', this code will instantiate MAX_CONTRACTS instances of the class. Each of these will have the value of 0 in all its properties. No actual contract can exist with these values so we will use this array of contracts, all with 'zero-ed' property values, to represent an empty set of contracts waiting to be filled in. We could have rewritten the constructor to have no assignment statements:

    Contract::Contract()
    {
    }

and thus have kept garbage in the values of the instances but why change what we have if it works? And, it is probably better that we know what an empty contract looks like, in case we accidentally try to use one.

We start then with zero contracts in the list. How do we keep track of this and update the count as we add contracts? There has to be some kind of counter that can be incremented when a new contract is added and decremented when a contract is deleted. Here we see that an array by itself will not work. There are at least two aspects to a list - the collection of objects and a counter.

We now have two knowledge responsibilities (probably data members) for our list data structure - the collection and the counter - and two function members - 'add' and 'delete'. Note that the approach just described here for discovering the class(es) needed, as well as their responsibilities, is somewhat different from what we did in chapter 5. It is, however, similar to something we hinted at earlier. It is not uncommon for object-oriented systems analysts to perform role plays in the process of doing a class analysis. If such a team were working on our problem, one member of the team would be a contract and one would be the list. In the process of adding the contract to the list, the team would notice, as we did, that the list needs to keep track of the number of contracts it has. Again, you are urged to perform analysis in groups and role play important scenarios, both to aid in your analysis and to understand the analyses described here. Remember, object oriented analysis is still more of an art than a science, so do what works and CHECK YOUR WORK CAREFULLY!!!

To check our work so far; see if there is more to this new class; and formalize our conclusions, we need to create a CRC card for our new class. At this point we have discovered two knowledge responsibilities:
Know the contracts on the list Know the number of contracts on the list

and two behavioral responsibilities (in addition to the constructors):
Add Contract Delete Contract.

There was a third italicized verb in the second paragraph of the problem narrative, - 'exist' - and, of course, instances do exist. However, beyond stating the obvious, this verb indicates no new functionality or responsibility for the class, so our CRC card looks as follows:


When doing the CRC card for 'Contract', we did not proceed to discuss collaborators because there was only one class to begin with. Now, however, we have two classes. Do either of these classes use the other as part of its work? Note that the class 'contract' can get along quite well without having any lists - we have written a program that demonstrates this. However, the class 'ListOfContracts' can't really exist without having a 'Contract' class to hold instances of. In other words, 'Contract' is a collaborator of 'ListOfContracts' and we will see in the code for 'ListOfContracts' that the class 'Contract' must be known.


With the CRC card in hand, we finish the analysis by checking to see if there are any new properties for our list class. The properties we have discovered so far (the collection of contracts and the counter to hold the number of contracts in the collection) were not found by looking at the underlined nouns in the problem narrative. Of course, they could have been discovered that way if, for example, the narrative had included a sentence such as, "The program will keep track of the number of contracts in the collection of contracts". But, no such sentence was included in the narrative. This points to the need to use every tool at one's disposal - including working as a team -in hopes that someone on the team will notice missing details.

The narrative does have two new nouns - 'limit' and 'contract ID'. The word 'limit' refers to the maximum number of contracts and it could be represented as a property of the class. However, it is already needed in the code as a constant, indicating the maximum size of the array. Therefore, it is somewhat redundant.

The notion of a 'contract ID', clearly, is not a property of 'ListOfContracts'. As we noted earlier, it is the Individual contract that has an ID. Technically, we probably should have made this ID a property of the 'Contract' class when we first discovered it but, as long as we were not deleting or adding contracts, it was unnecessary. Deletes change everything. When a user wants to delete a contract, they should not have to know where in the array the specific contract they want to delete is stored. In fact, given the notion of encapsulation, neither the user nor the programmer of the main program even knows that we are using an array to implement the list of contracts. What users should provide is some way of identifying the contract they want deleted - thus the contract ID. This ID will be used to search through the list looking for the contract to be deleted.

Figure 8.3 shows the modified CRC card for the Contract class.


B. Implications of Encapsulating the Array of Contracts
Our design has become more complex. We now have two classes and those two classes interact with each other. In addition, our use of contract ID's means we will have to change the simple way we previously accessed the individual elements of the array of contracts. No longer can the user enter a value that corresponds directly with an a specific location in the array.

At this point it is good practice for the design team to walk through (role play) the various processes involved in this program and see if the various member and non-member functions still work together as expected. It is amazing how beginners, who often have trouble visualizing how the various components of a program work together, will avoid this step, while experienced programmers, who would seem to have a better grasp of the interactions involved, will take advantage of this. In this 'text' we can't actually do a role play but we can simulate the process behind such.

Let's start with an analysis of the processes involved in simply displaying the information about a contract. After a 'D' has been entered to indicate that the user wants to display the information about a contract, the contract ID is requested. In the original program the user entered a contract number, then the function 'ProcessUserChoices' used this value as an index into an array of contracts and passed an element of the array of contracts to 'DisplayInfo'. First hint of trouble: the re-designed program does not provide the main program with direct access to any array. (The array is now encapsulated inside the list.) Nor does the new version use contract ID's as indices because ID's do not correspond to positions in the array of contracts. How then will the function 'ProcessUserChoices' get a contract to pass to 'DisplayInfo'?

So, we know there is a problem. Before running off to solve it, we should look at more of the program. We might gain some information that will guide us in devising a solution. What happens, then, when the user chooses to change the information about some contract. Again, a contract ID is entered and we run into the same problem. We need a way to get back the contract to be passed to the function that makes the changes. Not only that but there is the added problem that once the contract has been changed, it needs to be put back into the list and no mechanism seems to exist to do that. We could have the system delete the old contract and then add the new contract but that seems a bit convoluted.

Moving on, let's look at 'DisplayAll'. When the user chooses to display all the contracts, there is no need for any specific contract ID. But, we still have a problem - how does the function 'DisplayAll' get access to the contracts in the list! Remember, the array of contracts is encapsulated and, therefore, is unavailable to functions that are not members of 'ListOfContracts'.

The design for the processes to delete and add contracts seem to be the only parts that are OK . In the case of deleting, the user will enter the contract ID and this will be passed to the member function 'Delete' which will do all the work. To add a contract the user will enter all the information necessary, a contract instance will be created, and finally, the member function 'Add' will be called with the newly instantiated contract being passed as a parameter.

It makes sense that 'Add' and "Delete' work since they were planned as part of the new class, 'ListOfContracts'. The rest of the functions, however, are leftovers from a program that existed before we worried about adding and deleting or about using a list. Take a moment to think about what you might do to fix these functions before proceeding to the next section of this chapter.
Top of Section Main Menu Next Section