CHAPTER 8
|
Table of Contents
Learning C++:
An Index of Entry Points
2. The A reference document on the basic elements of C++.
3. The Patterns
|
Section III. The List: An Initial Look at Data Representation
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
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:
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:
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:
and two behavioral responsibilities (in addition to the constructors):
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
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.
|
|