Systematic and Structured Programming, Part 2
Step Three - Locating Methods and Creating Specifications
Once again, step two was not difficult. In fact, between writing steps one and two, you probably still don't have a whole 20 minutes invested in this process. That's just one of the benefits here.
Once again (again), you will also find that step three is just an expansion of step two, although you will be taking some new actions here. Mostly however, you will just be filling in areas that are guided by what you wrote in your previous steps.
If you are working through this with the web page, you should create a new QuadClass_StepThree.java file and copy your QuadClass_StepTwo.java code into it so that you don't overwrite your second step. You will be reminded again to make this change at the end of this web page.
Now, you must work your way through the program from top to bottom following the iterative refinement process. This time, you will be identifying the need for, and the use of, methods in your program.
Start here
Initialize the program
// initialize program
// initialize variables
// show title
There is still very little to do here, but we will create a method to conduct the print title operation
// initialize program
// initialize variables
// show title
You have specified that you want to print a title. This is not terribly complicated but it's a place to start
Consider the requirements you have specified related to printing the title:
- what do they have in common?
- the title will always be printed the same way
- what is different about each of them?
- in this case, nothing. Again the title will always be printed the same way
Taking a minute or two to consider this information will help you figure out how to design the necessary method
- it will print the title (process)
- it doesn't need any information to do its job (method parameter input)
- it will not conduct any processing and therefore will not return anything to the calling method (method return output)
- it will not capture any input from any devices but it will send output to the device: Monitor
- it will use a Console IO Class object to conduct the printing (dependencies)
So now, you create a specification for your method down below in the supporting methods area that looks like the following:
/*
Name: displayTitle
Process: displays the program title on the monitor
Method Input/Parameters: none
Method Output/Parameters: none
Method Output/Returned: none
Device Input/Keyboard: none
Device Output/Monitor: title displayed
Dependencies: Console IO Class tools
*/
This is also the point where you can create the stub method for later use. Creating the stub method will allow you to call the method when you write the step four part and it will be there for you when it comes time to conduct steps five and six:
/*
Name: displayTitle
Process: displays the program title on the monitor
Method Input/Parameters: none
Method Output/Parameters: none
Method Output/Returned: none
Device Input/Keyboard: none
Device Output/Monitor: title displayed
Dependencies: Console IO Class tools
*/
public static void displayTitle()
{
}
Make sure you don't have any errors after writing this code. Next up is the input operation to get the coefficients.
Get the coefficients from the user
// get coefficients from user
// get coefficient A
// get coefficient B
// get coefficient C
You have specified that you want to get the three coefficients from the user. This will certainly require one or more methods in order to keep the program modular (and to keep your main method from getting more complicated)
Consider the requirements you have specified related to getting the coefficients from the user:
- what do they have in common?
- each one of them will be prompted for a coefficient input
- each one of them will return an integer result (i.e., one of the coefficients)
- what is different about each of them?
- the prompt will be slightly different. For example the first prompt will ask for coefficient A, the second for coefficient B, and so on
- otherwise, they do the same thing by asking the user for a coefficient and acquiring it; that is a hint that a single method can be used to solve this problem
Taking a minute or two to consider this information will help you figure out how to design the necessary method
- it will prompt the user for the specified coefficient letter, it will acquire the coefficient from the user, and then it will return the integer coefficient to the calling method (i.e., the main method in this case) (process)
- it will need to know which coefficient is being prompted for (method parameter input)
- it will return an integer value that is the requested coefficient (method return output); at this point, it will not be necessary to use the method parameter output
- it will capture input from the device: Keyboard, and it will send output to the device: Monitor
- it will use a Console IO Class object to conduct the user interaction (dependencies)
So now, you create a specification for your method down below in the supporting methods area alphabetically after displayTitle that looks like the following:
/*
Name: promptForCoefficient
Process: prompt user for appropriate coefficient,
get coefficient, return coefficient
Method Input/Parameters: coefficient letter (char)
Method Output/Parameters: none
Method Output/Returned: acquired coefficient (int)
Device Input/Keyboard: user input
Device Output/Monitor: prompt displayed
Dependencies: Console IO Class tools
*/
public static int promptForCoefficient( char coefLetter )
{
return 0;
}
Note that it is required to place the return 0; statement in the method. If this is not written into the method, the compiler will complain that the method is not returning the data it had promised to return. Also note that since all of these methods will be in the same class as the main method, they will have to be static methods. Again, make sure there are no errors or warnings with Eclipse at this point.
Now you will write the name of the method in your program as shown. You can see how this would look right at this point here. Notice the re-use of the method; this is already evidence of good quality programming.
// get coefficients from user
// get coefficient A
// method: promptForCoefficient
// get coefficient B
// method: promptForCoefficient
// get coefficient C
// method: promptForCoefficient
Process the quadratic roots
// Process the quadratic roots
// calculate the discriminant
// calculate the square root of the discriminant
// calculate the denominator
// Calculate the roots
// calculate root one
// calculate root two
There are several actions to be taken here, but that just provides an opportunity to practice with simple methods
For the first operation ("calculate the discriminant"), you have specified that you want to calculate the discriminant (i.e., the calculations under the radical). As before, this will require a method in order to keep the program modular
Consider the requirements you have specified related to calculating the discriminant for every combination of coefficients the user provides:
- what do they have in common?
- each time the method is called, it will have to calculate b2 - 4ac
- what is different about each of them?
- the coefficients A, B, and C will likely be different every time the method is called
- otherwise, the method does the same thing by acquiring the three coefficients and calculating the discriminant
Taking a minute or two to consider this information will help you figure out how to design the necessary method
- it will accept the three coefficients, calculate the discriminant, and then return the result to the calling method (i.e., the main method in this case) (process)
- it will need to know all three coefficients (method parameter input)
- it will return an integer value that is the discriminant (method return output)
- it will only be conducting basic math operations, so it does not need to use any other methods (dependencies)
So now, you create a specification and the stub for your method down in the supporting methods area alphabetically before the getCoefficient method that looks like the following:
/*
Name: calcDiscriminant
Process: calculate discriminant with three coefficients
and return
Method Input/Parameters: three coefficients (int)
Method Output/Parameters: none
Method Output/Returned: calculated discriminant (int)
Device Input: none
Device Output: none
Dependencies: none
*/
public static int calcDiscriminant( int cofA, int cofB, int cofC )
{
return 0;
}
For the next operation ("calculate the square root of the discriminant"), the square root of the discriminant must be found. You could write a square root calculation method, but for purposes of this activity, it is much easier to use the class method sqrt. So, since you will be using the Math class method, you will not have to do an analysis of the problem, and you will not have to create a method. The method: Math.sqrt will be placed under this step two statement,
For the next operation ("calculate the denominator"), you have specified that you want to calculate the denominator of the quadratic equation. As before, this will require a method in order to keep the program modular
Consider the requirements you have specified related to calculating the denominator for every coefficient A the user provides:
- what do they have in common?
- each time the method is called, it will have to calculate 2 * A
- what is different about each of them?
- the coefficient A will likely be different every time the method is called
- otherwise, the method does the same thing by acquiring the coefficient and calculating the denominator
Taking a minute or two to consider this information will help you figure out how to design the necessary method
- it will accept the A coefficient, calculate the denominator, and then return the result to the calling method (i.e., the main method in this case) (process)
- it will need to know the coefficient A (method parameter input)
- it will return an integer value that is the denominator (method return output)
- it will only be conducting basic math operations, so it does not need to use any other methods (dependencies)
So now, you create a specification for your method up in the method prototype area alphabetically prior to calcDiscriminant that looks like the following:
/*
Name: calcDenominator
Process: calculate denominator with coefficient A
and return
Method Input/Parameters: coefficient A (int)
Method Output/Parameters: none
Method Output/Returned: calculated denominator (int)
Device Input: none
Device Output: none
Dependencies: none
*/
public static int calcDenominator( int coef_A )
{
return 0;
}
Finally, for the last root processing operations ("calculate root one" and "calculate root two"), you have specified that you want to calculate the two roots of the equation using the solution components you have already generated (i.e., the square root of the discriminant and the denominator). As usual, this will require a method in order to keep the program modular.
Consider the requirements you have specified related to calculating the root for every set of data the user provides:
- what do they have in common?
- each time the method is called, it will be provided with the coefficient B, the square root of the discriminant, and the denominator, all of which are components in the quadratic equation
- each time the method is called, it will have to calculate negative b + (either the positive or negative) discriminant, all divided by the denominator
- what is different about each of them?
- the square root of the discriminant must be positive to calculate one root, and negative to calculate the other root; that can be resolved by simply making the square root of the discriminant positive or negative when it is passed to the method as a parameter
- otherwise, the method does the same thing by acquiring the three components and calculating each individual root
Taking a minute or two to consider this information will help you figure out how to design the necessary method
- it will accept the three specified components, calculate the root, and then return the result to the calling method (i.e., the main method in this case) (process)
- it will need to know the coefficient B, the square root of the discriminant (passed either as a positive or negative value), and the denominator (method parameter input)
- it will return a double value that is one of the root solutions (method return output)
- it will only be conducting basic math operations, so it does not need to use any other methods (dependencies)
So now, you create a specification for your method down in the supporting methods area alphabetically after the calcDiscriminant method that looks like the following:
/*
Name: calcRoot
Process: calculate single root solution with previously
processed equation components, and return
Method Input/Parameters: coefficient B and the denominator (int),
and the square root of the discriminant (double)
Method Output/Parameters: none
Method Output/Returned: calculated single root (double)
Device Input: none
Device Output: none
Dependencies: none
*/
public static double calcRoot( int coef_B, int denominator, double discSqrt )
{
return 0;
}
Now that you have specified (i.e., created the specifications for) the methods you wish to use, you may fill in the appropriate areas in the main part of your program, as shown here
// Process the quadratic roots
// calculate the discriminant
// method: calcDiscriminant
// calculate the square root of the discriminant
// method: Math.sqrt
// calculate the denominator
// method: calcDenominator
// calculate the roots
// calculate root one
// method: calcRoot
// calculate root two
// method: calcRoot
Display the roots
// display roots
// display user input values
// display root one
// display root two
The actions are also pretty easy for output display, but you can again take advantage of the characteristics of methods if you will take the time to think it through. Consider the "what's in common/what's different" questions for this one more process
For the user input values, there isn't much reason to create a new method to do what a printString method can already do. Thus, we will plan on using the printString operation for that part.
For the root display operation ("display root one" and "display root two"), you have specified that you want to display the two roots. As usual, this will require a method in order to keep the program modular
Consider the requirements you have specified related to calculating the root for every set of data the user provides:
- what do they have in common?
- each time the method is called, it will be provided with a root solution, and the number of the root solution (either root 1 or root 2)
- each time the method is called, it will have to display the root number (1 or 2) and then the root solution related to that number
- what is different about each of them?
- the root number will be different and the root solution will be different
- otherwise, the method does the same thing by acquiring the root number and the root, and displaying useful information to the user
Taking a minute or two to consider this information will help you figure out how to design the necessary method
- it will accept the root number and the root, and it will display the root with its number on the screen (process)
- it will need to know the root number and the individual root solution (method parameter input)
- it will not return anything to the calling method, but it will display a result on the screen (device output)
- it will be conducting output operations using Console IO Class tools (dependencies)
So now, you create a specification for your method down in the supporting method area alphabetically after the calcDiscriminant method that looks like the following:
/*
Name: displayRoot
Process: display root number and root solution
Method Input/Parameters: root number (1 or 2) (int),
and root solution (double)
Method Output/Parameters: none
Method Output/Returned: none
Device Input: none
Device Output/Monitor: root number and root solution
Dependencies: Console IO Class I/O tools
*/
public static void displayRoot( int rootNum, double rootValue )
{
}
Note in this case, like the displayTitle, the method displays an output to the device (i.e., the monitor) but does not return any processed data back to the calling method (i.e., the main method). Thus, there is no return statement for this method.
With the display method specified, you can place it in the appropriate place in your code
// display roots
// display user input values
// method: printString
// display root one
// method: displayRoot
// display root two
// method: displayRoot
End the program
// end program
// display program end
You will actually need two more methods to show the end of the program, but like the square root method, these have also been written for you. You will simply be using the printString and printEndlinemethod for this part.
// end program
// display program end
// method: printString, printEndline
Wrapping Up Specifications and Stub Methods
The stub creation part of step three is mostly a management process so that your program will continue to compile correctly even as you move into step four. It is appropriate to do it in this step because this is where you are specifying and locating the methods you will use.
Having said that, creating these code components is as easy as following the instructions you gave yourself. It never needs to be any more difficult than this
Some more notes:
- This third step takes a little longer to write -- not that long -- but a little longer. However, if you consider that you have now created the bulk of the program and the remainder of your task is to just fill in the blanks you have now created, you have moved way ahead
- If you have been following this process carefully, you will notice that there are no parts in it where you fall back in your chair or on the floor and cry, "Why me . . . why me! This is sooooooooooo hard!" That does not seem to be necessary for this process. You just take one step at a time and you design and develop a program. Yes, if it is a non-trivial program, it will be complicated when you finish it; but no, it does not have to be complicated while you are developing it
- In order to conduct this part of the process, you must remember to create a new QuadClass_StepThree.java class and copy your QuadClass_StepTwo.java code into it before you make any changes. You want to keep your step two program exactly as it was so that if there are questions in the future about your overall strategy, you can go back and review the code
- Remember as you type in your method specifications, you must still make sure the program compiles without errors or warnings; in other words, make sure Eclipse is not showing any errors or warnings. This continues to be trivial because you are not adding much code. However, it remains important that no unknown issues pop up right now, and besides, it is a great habit to get into (that you will be using quite a bit in the next step)
This step -- in this page -- may seem long but it is mostly because code is typed and re-typed quite a bit. The actual step three takes no more time than the typing you need to do. Again, much of what you did in this step was just following instructions from the previous steps and much of what you will do in the succeeding steps will be following the instructions you created here.
To see the step three process in action, watch this video; then develop your step three code with or without the video as needed.