|
|
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 4 of 5
// In source packet in file coupling/ex3/Example3.java
class Example3 {
public static void main(String[] args) {
CoffeeCup cup = new CoffeeCup();
Liquid.convertOzToMl(16, cup);
//...
}
}
The problem here is that convertOzToMl() is now coupled to the CoffeeCup class. This is less flexible than the first version of convertOzToMl(), which returned the milliliters as an int. If later, someone wanted to convert ounces to milliliters for some purpose that didn't involve a coffee cup, they would
have to rewrite the method, write a different method, or create a CoffeeCup object just to hold the output.
In Figure 3 you can see a graphical depiction of this kind of method.

Figure 3. A bad utility method
A truly ugly utility method
The worst way to write the convertOzToMl() method (the way that yields the maximum coupling) is to take an input from a public static variable and put the output in another public static variable. A public static (but not final) variable in Java is equivalent in functionality and danger to global variables of C or C++. Here's an example:
// In source packet in file coupling/ex4/Liquid.java
// THIS APPROACH WORKS, BUT MAKES THE CODE HARD TO UNDERSTAND
// AND HARD TO CHANGE
class Liquid {
private static final double FL_OUNCES_PER_ML = 12.0/355.0;
private static final double ML_PER_FL_OUNCE = 355.0/12.0;
/**
* Converts fluid ounces to milliliters
*/
public static void convertOzToMl() {
double d = PurpleZebra.k * ML_PER_FL_OUNCE;
d += 0.5;
FlyingSaucer.q = (int) d;
}
}
// In source packet in file coupling/ex4/FlyingSaucer.java
class FlyingSaucer {
public static int q;
//...
}
// In source packet in file coupling/ex4/PurpleZebra.java
class PurpleZebra {
public static int k;
//...
}
To use the above version of convertOzToMl(), a programmer would have to do the following:
// In source packet in file coupling/ex4/Example4.java
class Example4 {
public static void main(String[] args) {
PurpleZebra.k = 16;
Liquid.convertOzToMl();
int mlFor16Oz = FlyingSaucer.q;
System.out.println("Ml for 16 oz is: " + mlFor16Oz);
}
}
To use this version of convertOzToMl(), client programmers would have to know a lot about the internal implementation of the method. They would have to know they
must put their ounces into the static variable PurpleZebra.k and grab the milliliters out of FlyingSaucer.q. By contrast, the "good" version of convertOzToMl() shown earlier in this article enabled programmers to understand how to use it simply by looking at the method's signature
and return type. This "ugly" version, because its signature and return type don't reveal all its inputs and outputs, is harder
to understand than the good version.
What's more, someone working on FlyingSaucer, not realizing that q was being used elsewhere, might delete the variable or use it for some other purpose. If q does get used for some other purpose and the program is multithreaded, the value of q could get trampled by a different thread after it is assigned the ounces but before convertOzToMl() gets a chance to use it.