Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

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

Designing fields and methods

How to keep fields focused and methods decoupled

  • Print
  • Feedback

Page 3 of 5

Some examples of state-change methods from the Java API are:

  • (In class StringBuffer) public StringBuffer append(int i) -- appends the string representation of the int argument to the StringBuffer
  • (In class Hashtable) public synchronized void clear() -- clears the Hashtable so that it contains no keys
  • (In class Vector) public final synchronized void addElement(Object obj) -- adds the specified component to the end of the Vector, increasing its size by one


Minimizing method coupling

Armed with these definitions of utility, state-view, and state-change methods, you are ready for the discussion of method coupling.

As you design methods, one of your goals should be to minimize coupling -- the degree of interdependence between a method and its environment (other methods, objects, and classes). The less coupling there is between a method and its environment, the more independent that method is, and the more flexible the design is.

Methods as data transformers
To understand coupling, it helps to think of methods purely as transformers of data. Methods accept data as input, perform operations on that data, and generate data as output. A method's degree of coupling is determined primarily by where it gets its input data and where it puts its output data.

Figure 1 shows a graphical depiction of the method as data transformer: A data flow diagram from structured (not object-oriented) design.

Figure 1. The method as data transformer

Input and output
A method in Java can get input data from many sources:

  • It can require that the caller specify its input data as parameters when it is invoked
  • It can grab data from any accessible class variables, such as the class's own class variables or any accessible class variables of another class
  • If it is an instance method, it can grab instance variables from the object upon which it was invoked


Likewise, a method can express its output in many places:

  • It can return a value, either a primitive type or an object reference
  • It can alter objects referred to by references passed in as parameters
  • It can alter any class variables of its own class or any accessible class variables of another class
  • If it is an instance method, it can alter any instance variables of the object upon which it was invoked
  • It can throw an exception


Note that parameters, return values, and thrown exceptions are not the only kinds of method inputs and outputs mentioned in the above lists. Instance and class variables also are treated as input and output. This may seem non-intuitive from an object-oriented perspective, because access to instance and class variables in Java is "automatic" (you don't have to pass anything explicitly to the method). When attempting to gauge a method's coupling, however, you must look at the kind and amount of data used and modified by the code, regardless of whether or not the code's access to that data was "automatic."

Minimally coupled utility methods

The least coupled method that is possible in Java is a utility method that:

  1. Takes input only from its parameters
  2. Expresses its output only through its parameters or its return value (or by throwing an exception)
  3. Accepts as input only data that is actually needed by the method
  4. Returns as output only data that is actually produced by the method


A good utility method
For example, the method convertOzToMl() shown below accepts an int as its only input and returns an int as its only output:

// In source packet in file coupling/ex1/Liquid.java
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 int convertOzToMl(int ounces) {
        double d = ounces * ML_PER_FL_OUNCE;
        d += 0.5;       // Must add .5 because (int) truncates
        return (int) d; // Result now rounded up if fraction >= .5
    }
}


Note that even though the above method makes use of a constant value, the constant value doesn't increase the method's coupling. (This is not only true conceptually, but also in how Java programs are compiled. As mentioned previously in this article, if a class uses a constant, even if it is from another class, its class file gets its own local copy of that constant value.)

To use this method, another method simply passes in the number of ounces and stores the returned number of milliliters:

// In source packet in file coupling/ex1/Liquid.java
class Example1 {
    public static void main(String[] args) {
        int mlFor8Oz = Liquid.convertOzToMl(8);
        int mlFor12Oz = Liquid.convertOzToMl(12);
        int mlFor16Oz = Liquid.convertOzToMl(16);
        System.out.println("Ml for 8 oz is: " + mlFor8Oz);
        System.out.println("Ml for 12 oz is: " + mlFor12Oz);
        System.out.println("Ml for 16 oz is: " + mlFor16Oz);
    }
}


Your aim when you write a utility method, such as convertOzToML(), should be to take input only from parameters and express output only through parameters or a return value or exception. In Figure 2, you can see a graphical depiction of this kind of method.

Figure 2. A good (minimally-coupled) utility method

Figure 2 shows a structure chart, from structured (not object-oriented) design. Although structure charts are not generally useful in an object-oriented design process, they are useful for graphically depicting the input and output to methods. For this reason, I'll be using structure charts in this article to help you visualize the coupling of methods.

A bad utility method
One way to increase the coupling of a utility method (or any other kind of method) is to pass objects that contain input data or are the recipient of output data, when the objects are not vital to the performance of the method. For example, perhaps when you first write convertOzToMl(), you plan always to put its output into a CoffeeCup object, as in:

// In source packet in file coupling/ex2/Example2.java
class Example2 {
    public static void main(String[] args) {
        CoffeeCup cup = new CoffeeCup();
        int amount = Liquid.convertOzToMl(16);
        cup.add(amount);
        //...
    }
}


If so, you might be tempted to write the convertOzToMl() method like this:

// In source packet in file coupling/ex3/Liquid.java
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(int ounces, CoffeeCup cup) {
        double d = ounces * ML_PER_FL_OUNCE;
        d += 0.5;
        cup.add((int) d);
    }
}


So you could use it like this:

  • Print
  • Feedback

Resources
  • The Heisenberg Uncertainty Principle states that we can't know both the position and the momentum of elementary particles, because the act of measuring one of these values changes the other. Put another way, if elementary particles were objects, they wouldn't have any state-view methods, because you couldn't determine their state (in this case, position and momentum) without changing that state.
  • Recommended books on Java Design http://www.artima.com/designtechniques/booklist.html
  • Source packet that contains the example code used in this article http://www.artima.com/flexiblejava/coupling.html
  • The discussion forum devoted to the material presented in this article. http://www.artima.com/flexiblejava/fjf/fieldsmethods/index.html
  • Object Orientation FAQ http://www.cyberdyne-object-sys.com/oofaq/
  • 7237 Links on Object Orientation http://www.rhein-neckar.de/~cetus/software.html
  • The Object-Oriented Page http://www.well.com/user/ritchie/oo.html
  • Collection of information on OO approach http://arkhp1.kek.jp:80/managers/computing/activities/OO_CollectInfor/OO_CollectInfo.html
  • Design Patterns Home Page http://hillside.net/patterns/patterns.html
  • A Comparison of OOA and OOD Methods http://www.iconcomp.com/papers/comp/comp_1.html
  • Object-Oriented Analysis and Design MethodsA Comparative Review http://wwwis.cs.utwente.nl:8080/dmrg/OODOC/oodoc/oo.html
  • Patterns discussion FAQ http://gee.cs.oswego.edu/dl/pd-FAQ/pd-FAQ.html
  • Implementing Basic Design Patterns in Java (Doug Lea) http://g.oswego.edu/dl/pats/ifc.html
  • Patterns in Java AWT http://mordor.cs.hut.fi/tik-76.278/group6/awtpat.html
  • Software Technology's Design Patterns Page http://www.sw-technologies.com/dpattern/
  • Synchronization of Java Threads Using Rendezvous http://www-cad.eecs.berkeley.edu/~jimy/classes/rendezvous/
  • Design PatternsElements of Reusable Object-Oriented Software, In Java http://www.zeh.com/local/jfd/dp/design_patterns.html
  • Another example of obvious content from Bill Venners http://www.artima.com/bv/music/obvioussong.html