Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 3 of 5
To increase the method cohesion of the previous CoffeeCup class, you could divide the functionality performed by modify() into two methods, add() and remove():
// In Source Packet in file cohesion/ex2/CoffeeCup.java
// THIS APPROACH WORKS, BUT MAKES THE CODE HARD TO UNDERSTAND
// AND HARD TO CHANGE
public class CoffeeCup {
private int innerCoffee;
public void add(int amount) {
innerCoffee += amount;
}
public int remove(boolean all, int amount) {
int returnValue = 0;
if (all) {
// set innerCoffee to 0
// ignore parameter amount
int allCoffee = innerCoffee;
innerCoffee = 0;
returnValue = allCoffee; // return all coffee
}
else {
// remove the amount of coffee passed as amount
int sip = amount;
if (innerCoffee < amount) {
sip = innerCoffee;
}
innerCoffee -= sip;
returnValue = sip; // return removed amount
}
return returnValue;
}
}

Figure 2: Passing control down to remove().
This is a better design, but it's not quite there yet. Although the add() method does not require you to pass down control, the remove() method still does. The boolean parameter all indicates to the remove method whether or not to remove all coffee (a spill) or to remove some coffee (a sip). In the case of a sip, the amount parameter indicates the amount of coffee to remove (the size of the sip). The graphical depiction of the remove() method, shown in Figure 2, shows a blackened circle heading down for the all parameter just as modify() had a blackened circle heading down for the action parameter. It also includes a parameter, amount, that is not always used, just as modify() is not always used. For remove(), if all is false, amount indicates the amount of coffee to remove. If all is true, amount is ignored.
A better design for the CoffeeCup class is to divide remove() into two more methods, neither of which accept control data as input or have parameters that are used only part of the time.
Here remove() has been divided into releaseOneSip() and spillEntireContents():
// In Source Packet in file cohesion/ex3/CoffeeCup.java
class CoffeeCup {
private int innerCoffee;
public void add(int amount) {
innerCoffee += amount;
}
public int releaseOneSip(int sipSize) {
int sip = sipSize;
if (innerCoffee < sipSize) {
sip = innerCoffee;
}
innerCoffee -= sip;
return sip;
}
public int spillEntireContents() {
int all = innerCoffee;
innerCoffee = 0;
return all;
}
}
As you can see, the process of removing input data used for control yields more methods, each with a more focused functionality. Instead of indicating your wishes to one comprehensive method by passing down a command as a parameter, you call a different method. For example, instead of saying:
// In Source Packet in file cohesion/ex1/Example1.java
class Example1 {
public static void main(String[] args) {
CoffeeCup cup = new CoffeeCup();
// ignore bogus return value of modify() in ADD case
cup.modify(CoffeeCup.ADD, 355);
int mlCoffee = cup.modify(CoffeeCup.RELEASE_SIP, 25);
// 2nd parameter is unused in SPILL case
mlCoffee += cup.modify(CoffeeCup.SPILL, 0);
System.out.println("Ml of coffee: " + mlCoffee);
}
}
You say:
// In Source Packet in file cohesion/ex3/Example3.java
class Example3 {
public static void main(String[] args) {
CoffeeCup cup = new CoffeeCup();
cup.add(355);
int mlCoffee = cup.releaseOneSip(25);
mlCoffee += cup.spillEntireContents();
System.out.println("Ml of coffee: " + mlCoffee);
}
}
As described earlier, this approach to method design yields code that is easier to understand because each method is responsible
for performing one conceptual function, and the method's name can describe that one function. Such code is also easier to
understand because the data passed in and out are always used and valid. In this example,
add(int),
int releaseOneSip(int),
spillEntireContents() are easier to understand at first glance than the
int modify(int, int)
In addition, this approach to method design yields code that is more flexible, because it is easier to change one functionality
without affecting the others. For example, if you wanted to make some adjustments to the spilling behavior of the coffee cup
class with modify(), you would have to edit the body of modify(). Because the code for spilling is intermingled in modify() with the code for sipping and adding, you might inadvertently introduce a bug in the adding behavior when you enhance the
spilling behavior. In the CoffeeCup class with separate methods for adding, spilling, and sipping, your chances are better that you can enhance the spilling
behavior without disturbing the adding and sipping behaviors.
Functionally cohesive methods also increase code flexibility because they make fewer assumptions about the order in which particular actions are performed. Here is an example of a method that is not very functionally cohesive because it assumes too much:
// In Source Packet in file cohesion/ex4/CoffeeCup.java
class CoffeeCup {
private int innerCoffee;
private int innerCream;
private int innerSugar;
private static final int CREAM_FRACTION = 30;
private static final int SUGAR_FRACTION = 30;
public void add(int amountOfCoffee) {
innerCoffee += amountOfCoffee;
innerCream += amountOfCoffee/CREAM_FRACTION;
innerSugar += amountOfCoffee/SUGAR_FRACTION;
}
//...
}
This CoffeeCup object keeps track not only of the amount of coffee it contains (innerCoffee), but also of the amount of cream (innerCream) and sugar (innerSugar). As you would expect, the add() method accepts an amount of coffee to add, then increments innerCoffee by that amount; however, add() doesn't stop there. It assumes that anyone wishing to add coffee to a cup also would want to add some cream and sugar, in
fixed amounts relative to the amount of coffee added. So add() goes ahead and adds the cream and sugar as well.
The design of this method reduces code flexibility because later, if a programmer wanted to add coffee with cream, but no sugar, this method would be of no use. A more flexible design would be:
// In Source Packet in file cohesion/ex5/CoffeeCup.java
class CoffeeCup {
private int innerCoffee;
private int innerCream;
private int innerSugar;
public void addCoffee(int amount) {
innerCoffee += amount;
}
public void addCream(int amount) {
innerCream += amount;
}
public void addSugar(int amount) {
innerSugar += amount;
}
//...
}
These methods are more functionally cohesive because they each do one thing. This design is more flexible because the programmer can call any of the methods at any time and in any order.