| |
Main Menu | Next Chapter |
A. The Overall Design
We have new user options to add and a whole new class to work with. It's time to integrate all this into the program code in the file containing 'main'. In chapter six we developed a structure chart for a simpler version of this program. The first part of this chart remains the same, with 'main' calling 'ProcessUserChoices', 'DisplayIntro' and 'DisplayClosingMessage'. However, 'ProcessUserChoices' has gotten more complex.
That is because here and there in this chapter we have added functionality to the program. In Section I above we talked about adding the ability to add and delete contracts, while in Section II we discussed the need for the 'InitializeInstances' and 'DisplayAll' functions. We also now have to get contract ID's from the user. There are enough new or modified functions that a revised structure chart would be useful.
What makes 'ProcessUserChoices' complex is that it handles all the processing for each option. Therefore, one way to simplify this function would be to create functions that handle all the processing for each user option and then have 'ProcessUserChoices' simply call these functions. Only one function call is removed from 'ProcessUserChoices', the call to 'GetContractID', but all the inner loops are removed. As the structure chart in Figure 8.7 shows, 'DisplayIntro' and 'DisplayClosingMessage' still do not have any function calls in them - they do not have any boxes hanging off them. 'ProcessUserChoices' is still at the heart of the program and it does make a number of function calls.
void ProcessUserChoices()
{
// Code to create the list of contracts
ListOfContracts contracts;
InitializeInstances(contracts);
bool done = false; // Is the user finished processing contracts?
char choice;
while (!done)
{ choice = GetOperatorChoice();
switch (choice)
{ case 'D':
case 'd':
DisplayContract(contracts);
break; // case 'd'
case 'C':
case 'c':
ChangeContract(contracts);
break; // case 'c'
case 'L':
case 'l':
DisplayAllContracts(contracts);
break;
case 'A':
case 'a':
AddContract(contracts);
break;
case 'E':
case 'e':
DeleteContract(contracts);
break;
case 'Q':
case 'q':
cout << "Do you want to really want top quit (Y) or (N)\n";
char answ;
cin >> answ;
if ((answ =='Y') || (answ == 'y'))
{
done = true;
}
break;
default:
cout << "Invalid choice. Please try again";
choice = GetOperatorChoice();
} // end switch
}
}
Clearly the code is much easier to read. Of course, we need to declare and define the new functions 'DisplayContract', 'ChangeContract' 'AddContract', 'DeleteContract', and 'DisplayAllContracts'. We trade cleaner code for a bit of extra work.
A few points to clarify:
Writing the declarations should now be simple so let's examine the code for these functions. The code for 'DisplayContract' and "ChangeContract' borrows from the code that used to be in the switch statements but has to be changed to reflect the fact that we are now using a list of contracts. As before, the user is asked for a contract ID (via a call to 'GetContractID'), and the code then loops until the user enters a 0 as the ID. (Remember, this allows the user to continue to display or change contracts without having to repeatedly enter a 'D' for 'Display or 'C' for Change.)
Inside the loops for both these functions the code is changed because the main program no longer has direct access to the array of contracts. We start with 'DisplayContract'. It must first use the list member function 'FindContract' to see if a contract with the entered ID exists on the list. If so, 'FindContract' returns both TRUE and the contract itself. This contract is then passed to the function 'DisplayInfo' that we developed in Chapter 6, Section III. . If no contract with this ID is found, 'FindContract' returns FALSE and an error message is output. Here is the code:
void DisplayContract(ListOfContracts& contracts)
{ int contractID;
Boolean found;
Contract contract;
contractID = GetContractID();
while (contractID != 0)
{ found = contracts.FindContract(contractID, contract);
if (found)
{ clrscr();
DisplayInfo(contract);
}
else
{ cout << "\nContract " << contractID << " is not in list.\n";
}
contractID = GetContractID();
}
}
The function 'ChangeContract' is almost the same except that inside the loop the function 'ChangeInfo' is called followed by the List member function 'ReplaceContract'. (Remember that the modified contract needs to be replaced on the list.) Again, here is the code:
void ChangeContract(ListOfContracts& contracts)
{ int contractID;
Boolean found;
Contract contract;
contractID = GetContractID();
while (contractID != 0)
{ found = contracts.FindContract(contractID, contract);
if (found)
{
ChangeInfo(contract);
contracts.ReplaceContract(contract);
}
else
{ cout << "\nContract " << contractID << " is not in list.\n";
}
contractID = GetContractID();
}
}
The function 'DisplayAllContracts' is simple – it just calls the list member function 'DisplayAll' to handle all the work.
void DisplayAllContracts(ListOfContracts& contracts)
{ contracts.DisplayAll();
}
We now look at 'AddContract' and 'DeleteContract'. Like 'DisplayContract' and 'ChangeContract', these two functions begin by asking for a contract ID and then loop until the user enters a 0. In the case of 'AddContract', the code inside the loop consists of first, a call to a function, 'CreateContact', that fills a new contract with information supplied by the user and second, a call to the list member function 'Add' (whose code and description is found here). "DeleteContract' is even simpler in that it only requires a call to the list member function 'Delete' (whose code and description is found here). Here is the code:
void AddContract(ListOfContracts contracts)
{ int contractID;
contractID = GetContractID();
Contract contract;
while (contractID != 0) // The user wants to add another contract
{ CreateContract(contractID, contract);
contracts.Add(contract);
contractID = GetContractID();
}
}
void DeleteContract(ListOfContracts& contracts)
{ int contractID;
contractID = GetContractID();
while (contractID != 0) // The user wants to delete a contract
{ contracts.Delete(contractID);
contractID = GetContractID();
}
}
We close our discussion of code with a look at 'InitializeInstances'. In Section II we observed that this function could take any number of forms, depending on how we want to carry out the task of creating the initial set of instances. The version we use here remains essentially the same as the one in Section II, except that we need to call the list member function 'Add'. This is necessary because, as we already noted, the main program does not have direct access to the array of contracts. The complete code for this is in the file 'ch8tst5.cpp'. Here we will look at how the first two contracts are initialized onto the list.
Contract contract;
contract.ChangeID(1111);
contract.ChangeSquareFootage(1000);
contract.ChangeNumDesks(3);
contract.ChangeNumDays(5);
contracts.Add(contract);
contract.ChangeID(2222);
contract.ChangeSquareFootage(500);
contract.ChangeNumDesks(10);
contract.ChangeNumDays(3);
contracts.Add(contract);
Note how only one contract is instantiated. To add the first contract to the list, this one contract is filled with the correct data and 'Add' is called. Then, to add the second contract to the list, the same contract is filled with the correct data for contract two and 'Add' is called again. Since 'Add' copies whatever it is given onto to the list, the single contract in this code is nothing but a placeholder for whatever information is being entered by the user. This process can be repeated until all contracts have been added to the list.
B. Summary
We have now designed and implemented a program with real potential. It allows users to view, modify, add, and delete contracts. We also have a general pattern - the list pattern - to handle a whole range of problems. Whether one wants to keep track of houses, swimming pools, people or whatever, the general framework for lists described here could be used. In fact, if the class types were changed to represent 'houses' or swimming pools or whatever, the main program would require little change. Try and remember that much of programming involves reusing what you or someone else has already designed, implemented, and tested. Saving work and avoiding bugs is part of what it is all about.
Of course, the final step is to compile, link, run, and test this
code. Follow the procedure you used in chapters 5 and 6 to get
your program running. The only trick is that now there are three
.cpp files to link. (Borland C++ users can click here to
get further instructions. You can find all the code in the files, 'common.h', 'contrct2.h', 'contrct2.cpp', 'ch8list2.h', 'ch8list2.cpp', and 'ch8tst5.cpp'.
This has been a long chapter. Click here if you would like to read a more detailed summary
| |
Main Menu | Next Chapter |