The Structured Programming movement (Djikstra, Hoare, Wirth, the Pascal language, etc.) first addressed the problem of overly complicated control structures. The conclusion was that control structures would be easier to understand, maintain, and validate if they had a single entry point. The main violator of this principle was the goto statement. For example:
int n = 0;
while (n++ < 10)
{
A: cout << "n = "
<< n << endl;
}
cout << "while command
exited\n";
goto A;
Unfortunately, many programmers take this idea too far and tend to avoid writing control structures with multiple exit points, which, ironically, can greatly simplify a control structure.
Half way through a task that's being iterated we may discover that there is no point in completing the task. Either a new iteration of the task should begin or no further iterations of the task are needed. In order to maintain a single exit point for the iteration, we need to introduce complicated multi-way conditionals (else-if, else-if, else-if, ...):
while(more) {
if (num == 0) {
cout <<
"Quitting\n";
more = false;
} else if (num < 0) {
cout << "Error: input
must be positive\n";
} else {
cout << "Result = "
<< sqrt(num) << '\n';
}
}
Alternatively, we can use the continue command to immediately start a new iteration of the task, or a break command to terminate the current task as well as further iterations. This eliminates the need for multi-way conditionals:
while(true) {
if (num == 0) {
cout <<
"Quitting\n";
break;
}
if (num < 0) {
cout << "Error: input
must be positive\n";
continue;
}
cout << "Result = "
<< sqrt(num) << '\n';
}
Function blocks can be simplified by providing multiple exits. For example, the following function uses a multi-way conditional to set a local variable:
double tax(double income) {
double tax;
if (income < 0)
throw AppError("income must be
non-negative");
else if (income < 10000)
tax = 0;
else if (income < 20000)
tax = .2 * income;
else if (income < 35000)
tax = .3 * income;
else if (income < 50000)
tax = .5 * income;
else
tax = .75 * income;
return tax;
}
Instead, we can return a value as soon as the value as known or throw an exception as soon as an error is detected:
double tax(double income) {
if (income < 0)
throw AppError("income must be
non-negative");
if (income < 10000) return 0;
if (income < 20000) return .2 *
income;
if (income < 35000) return .3 *
income;
if (income < 50000) return .5 *
income;
return .75 * income;
}
A method has become too long or a task appears in many methods.
The investment calculator contains a long method that computes and displays the future value of an investment based on a 2.5% monthly rate of return for one year:
public class InvestmentCalculator {
public static void value(double prin)
{
double rate = .025;
double term = 12;
double eVal = 0;
double
temp1 = 1 + rate;
double temp2 = Math.pow(temp1,
term);
eVal = prin * temp2;
System.out.println("+++++++++++++");
System.out.println("rate =
" + rate);
System.out.println("investment
= " + prin);
System.out.println("term =
" + term);
System.out.println("value =
" + eVal);
System.out.println("+++++++++++++");
}
public static void main(String[] args)
{
value(12000);
}
}
In the interests of decoupling presentation logic from application logic, let's apply the extract method refactoring to the output task. Unfortunately, this task uses some of the local variables declafred earlier, so these will need to be passed as parameters to the new method:
public class InvestmentCalculator {
public static void value(double prin)
{
double rate = .025;
double term = 12;
double eVal = 0;
double temp1 = 1 + rate;
double temp2 = Math.pow(temp1,
term);
eVal = prin * temp2;
printResult(rate, prin, term, eVal);
}
public static void printResult(
double rate, double prin, double
term, double eVal) {
System.out.println("+++++++++++++");
System.out.println("rate =
" + rate);
System.out.println("investment
= " + prin);
System.out.println("term =
" + term);
System.out.println("value =
" + eVal);
System.out.println("+++++++++++++");
}
public static void main(String[] args)
{
value(12000);
}
}
Of course printResult does have a rather long parameter list. Fortunately, there are refactorings for dealing with this problem.
Next, we turn our attention to the calculation of the future or expected value. Applying extract method here is trickier because it modifies the eVal local in the caller's environment. In this case we must return the computed value as a result:
public class InvestmentCalculator {
public static void value(double prin)
{
double rate = .025;
double term = 12;
double eVal = expectedValue(rate,
prin, term);
printResult(rate, prin, term, eVal);
}
public static double expectedValue(
double rate, double prin, double
term) {
double eVal = 0;
double temp1 = 1 + rate;
double temp2 = Math.pow(temp1,
term);
eVal = prin * temp2;
return eVal;
}
public static void printResult(
double rate, double prin, double
term, double eVal) {
System.out.println("+++++++++++++");
System.out.println("rate =
" + rate);
System.out.println("investment
= " + prin);
System.out.println("term =
" + term);
System.out.println("value =
" + eVal);
System.out.println("+++++++++++++");
}
public static void main(String[] args)
{
value(12000);
}
}
Notice that temp1 and temp2 are placed inside of the new method. This is because they are only needed in the calculation of the expected value.
What happens if the extracted method needs to modify several of the caller's local variables?
Solution 1: The extracted method can return an object, the fields of which are the new values of the local variables.
Solution 2: If the local variables can be passed by reference, then the extracted method can change them directly.
Just as the Structured Programming movement fingered the goto statement as the source of needlessly complex control structures, the Object-Oriented Programming movement expands the web of blame to multi-way conditionals.
Assume a fleet contains many types of aircraft.

Although Aircraft defines default takeoff, fly, and land methods, these methods are overridden in the subclasses by more appropriate algorithms. The Fleet.takeoff() method uses a multi-way conditional and the type of the array component to determine which takeoff() function to call:
class Fleet {
private static final int MAX = 100;
private Aircraft[] members = new
Aircraft[MAX];
private int size = 0;
public void takeoff() {
for(int i = 0; i < size; i++)
{
if (members[i] instanceof Blimp)
((Blimp)members[i]).takeoff();
else if (members[i] instanceof
Airplane)
((Airplane)members[i]).takeoff();
else if (members[i] instanceof
Helicopter)
((Helicopter)members[i]).takeoff();
else
System.err.println("unrecognized
aircraft");
}
}
// etc.
}
In addition to being complicated, explicit dispatch mechanisms like this make adding new Aircraft subclasses difficult. We must locate each one and add a new else-if clause. The situation is made additionally complicated by the fact that such control structures are usually found in clients of the Aircraft hierarchy.
Of course the dynamic dispatch mechanisms provided by most object-oriented languages already does this at runtime:
class Fleet {
private static final int MAX = 100;
private Aircraft[] members = new
Aircraft[MAX];
private int size = 0;
public void takeoff() {
for(int i = 0; i < size; i++)
members[i].takeoff();
}
// etc.
}