| |
Main Menu | Next Section |
| Section III: Output, Calculation, and Display Functions | Section I: Decomposition | Section II: Functions | Section IV: Parameters |
| Section V: Tracing | Section VI: Final Thoughts on Redesigning the Employee Salary Problem |
A. Output Functions
It's now time to work on some of the other functions. If you have
followed the discussion in the previous section, you should find
it easy to code "GetHoursWorked" so let's try OutputSalary
next. It turns out that 'OutputSalary' is almost the opposite
of 'GetRateOfPay' and demonstrates another simple but important
design pattern - the "Basic Output" pattern. The design starts
as follows:
OutputSalary
Purpose: To output the salary of an employee
Goal: The screen displays salary
The only new idea here is that a 'goal' can include how the screen looks. Notice that there is no internal state change. When doing an output to a monitor, the system retrieves the value(s) found in one or more memory locations and displays those values on the screen. However, the contents of those memory locations are not changed.
We move now to asking our two questions. First:
If someone asks you to go to the board and write down the value
they are thinking of, what information do you need from them?
What you need, of course, is the value they are thinking of. The
same with our output function. It needs whatever is to be output
- the salary in this case. Now, for question number two:
When you are finished writing the value on the board (using the
same example), is there some information you return to whomever
made the request - other than to say you are done? No! Similarly,
with this and most output functions - nothing is returned. The
design then becomes:
OutputSalary
Purpose: To output the salary of an employee
Goal: The screen displays salary
Receives: <salary>, a double
Returns NONE
And finally, the algorithm:
Algorithm:
Most functions whose purpose is to output a value have the same
design. This then is an example of our second design pattern,
the "Basic Output" pattern:
Purpose: To output some value(s) Goal: The screen displays the value(s)
Receives: The value(s) Returns: NONE
Algorithm: Output the value(s)
As before we need to declare and define this function. First the
declaration:
This time we put the word 'void' in front of the function name
because the function returns nothing. Inside the parentheses we
place the type and name of the one variable that is to be received.
As with all parameters, this is a local variable, known only inside
this function. We could have chosen any name we wanted, including
the variable name 'fullSalary' used in 'main'.
Also, as before, we need to define this function but this is easy given our algorithm.
Here the code is even simpler than in 'GetRateOfPay' - one line! There is no 'return' instruction because there is nothing to return.
Such one line functions are not uncommon, but why would we want
them? As noted above, they allow us to modularize our code. Later,
we can make this output as complex as we want or we can even experiment
with different forms of output without changing any other part
of the code. Even experienced programmers are often tempted to
not use functions when they first start writing a program. They
know, however, that a section of code that looks simple at the
moment can easily become complex as the requirements and understanding
of the program grow. In the long run, modularity through the use
of functions makes the programmer's job easier and helps avoid
errors. Trust us for now if you are not already converted!
Before reading on, see if you can integrate this code into the
original program. When you are finished, compare what you have
done with the code in the file ch4prg1.cpp.
Points to stress about this code:
B. Functions That Calculate a Value
We move on to the function that calculates the employee's salary and again start with the design. As usual, if the task decomposition process has been done correctly, it is easy to state the purpose and goal of this function.
CalculateSalary
Purpose: To calculate an employee's salary
Goal: <employeeSalary>, a double, contains the employee's
salary
To determine the receives and returns we do what we have done in the previous two cases and ask our questions.
1. What, if any, data does the called function need
from the calling function to accomplish its task?
2. What, if any, data does the calling function expect back?
Anytime a function has as its purpose some kind of a calculation one can assume that it needs to return the result of that calculation. One should then check to see if the function needs to receive the values involved in the calculation - perhaps not including constants. We therefore have the basis for another design pattern - Pattern 'C' of the Function Design Patterns .
Since 'CalculateSalary' has no other way of knowing the rate of pay and the hours worked, it does have two receives - the rate of pay and the hours worked. The value calculated and returned is the salary. Here then is the result of the design phase including an algorithm that reflects the code we wrote in chapter two.
CalculateSalary
Purpose: To calculate an employee's salary
Goal: <employeeSalary>, a double, contains the employee's salary
Receives: <rate> a double, <hours> a double
Returns: <employeeSalary>
Algorithm:
If Hours > 40 then
{
Regular Salary = 40 * Rate
Overtime Rate = Rate * 1.5
Overtime Salary = (Hours - 40) * Overtime Rate
Employee Salary = Regular Salary + Overtime Salary
}
else
{
Employee Salary = Hours * Rate
}
Note that we provide a name and type for each value to be received but
only a type for the value to be returned. The calling function
will use the returned value however it wishes, so it and not the
called function has the responsibility of providing a variable
name. On the other hand, the received values are used in the function's code - as 'rate' and 'hours' will be used in this function's code.
The only new idea here is that there are now two local variables
inside the parentheses, reflecting the fact that two items are
received by the function. Note that there is a comma separating
the two items, which, by the way, are technically called parameters.
The function definition is simply a translation of the algorithm. For us it is even easier than that because we have already written the code in chapter two - see the 'if' statement in the function 'main above. We only need to change 'hoursWorked' to 'hours' and 'rateOfPay' to 'rate' to reflect the names of our local variables. Thus, the definition looks as follows:
double CalculateSalary(double rate, double hours)
{ double regularSalary;
double overtimeSalary;
double fullSalary;
double overtimeRateOfPay;
if (hours > REGULAR_HOURS)
{ regularSalary = REGULAR_HOURS * rate;
overtimeRateOfPay = rate * OVERTIME_ADJUSTMENT;
overtimeSalary = (hours - REGULAR_HOURS) * overtimeRateOfPay;
fullSalary = regularSalary + overtimeSalary;
}
else
{ fullSalary = hours * rate;
}
return fullSalary;
}
Putting this function's declaration
and definition in their proper places in the full program are
left as an exercise for you. We do, however, need to discuss the
code that will call this function.
In the previous versions of this program, 'main' included the
code for the algorithm we just discussed. Now we witness a drastic reduction and
simplification of the 'for' loop found in 'main.':
for (int count = 0; count < NUM_TIMES; count++)
{ rateOfPay = GetRateOfPay();
hoursWorked = GetHoursWorked();
fullSalary = CalculateSalary(rateOfPay, hoursWorked);
OutputSalary(fullSalary);
}
The function call
is like all the others except that there are two parameters (two values to be passed to the function definition) and the parameters are separated by a comma. Two parameters are needed of course, because 'CalculateSalary' has been declared as receiving two values.
Notice how easy the loop' is to comprehend. We are looking at something like an executive summary. The key steps are all there but the details have been removed. Again, this is an important part of complexity reduction through functional decomposition.
C. The Display Functions
The only two functions left to discuss are the two display functions. They are both pretty much the same so let's focus on 'DisplayIntroScreen'. A quick analysis indicates that its sole purpose is to output a message. Since it knows its message, it does not need to receive anything. As with most output functions (see the discussion of 'OutputSalary'), it also does not need to return anything and has a very simple algorithm. Here then is the design:
DisplayIntroScreen
Purpose: To output a introductory message
Goal: The introductory message is displayed
Receives: NONE
Returns: NONE
Algorithm
The function declaration looks as follows:
The code to be included in the definition is made up of some number
of 'cout' lines to output the desired introductory message.
That concludes our work on this modularized version of
this program. A final version of this code is available
but you are urged to attempt it yourself before reviewing that
code. As part of that effort you might want to review the basic
function design patterns introduced
in this chapter.
| |
Main Menu | Next Section |