The Artima Developer Community
Design Techniques | Book List | Print | Email | First Page | Previous | Next
Sponsored Link

Designing Fields and Methods
How to Keep Fields Focused and Methods Decoupled
by Bill Venners
First Published in JavaWorld, March 1998

Page 1 of 7  >>

Advertisement

Summary
This installment of the Design Techniques column shows how some fundamental software design techniques, like avoiding special data values and minimizing method coupling, apply to Java.


This month's installment of Design Techniques is the second in a mini-series of columns about designing objects. In last month's column, which covered designing objects for proper initialization, I talked about how to design constructors and initializers. This month and next month I'll discuss design principles for the actual fields and methods of the class. After that, I'll write about finalizers and show how to design objects for proper cleanup at the end of their lives.

The material for this article (avoiding special data values, using constants, minimizing coupling) and the next article (maximizing cohesion) may be familiar to many readers, as the material is based on general design principles that are quite independent of the Java programming language. Nevertheless, because I have encountered so much code over the years that doesn't take advantage of these principles, I think they deserve to be restated from time to time. In addition, in this article I attempt to show how these general principles apply to the Java language in particular.

Designing fields
In designing fields, the main rule of thumb is to avoid using one variable to represent multiple attributes of a class. You can violate this rule by denoting special values within a variable, each with its own special meaning.

As used here, an attribute is a distinguishing characteristic of an object or class. Two attributes of a CoffeeCup object, for example, could be:

To take a closer look at this rule, imagine you are designing a CoffeeCup class for the virtual café described in last month's Design Techniques column. Assume you want to model whether or not a coffee cup in your virtual café has been washed and is ready for use by the next customer. With this information on hand, you can ensure that you don't reuse a coffee cup before it has been washed.

If you decide you only care whether or not a cup has been washed if it is empty, you could use a special value of the innerCoffee field, which normally is used to keep track of the amount of coffee in the cup, to represent an unwashed cup. If 473 milliliters (16 fluid ounces) is the maximum amount of coffee in your largest cup, then the maximum value of innerCoffee normally would be 473. Thus, you could use an innerCoffee value of, say, 500 (a special value) to indicate an empty cup that is unwashed:

// In source packet in file fields/ex1/CoffeeCup.java
class CoffeeCup {

    private int innerCoffee;

    public boolean isReadyForNextUse() {

        // If coffee cup isn't washed, then it's
        // not ready for next use
        if (innerCoffee == 500) {
            return false;
        }
        return true;
    }

    public void setCustomerDone() {
        innerCoffee = 500;
        //...
    }

    public void wash() {
        innerCoffee = 0;
        //...
    }
    // ...
}

This code will give CoffeeCup objects the desired behavior. The trouble with this approach is that special values aren't readily understood, and they make code harder to change. Even if you describe special values in a comment, it may take other programmers longer to understand what your code is doing. Moreover, they may never understand your code. They may use your class incorrectly or change it such that they introduce a bug.

For example, if later someone adds a 20 ounce cup to the offerings of the virtual café, it would then be possible to hold up to 592 milliliters (ml) of coffee in a cup. If a programmer adds the new cup size without realizing you are using 500 ml to indicate that a cup needs washing, it is likely that a bug will be introduced. If a customer in your virtual café bought a 20 ounce cup, then took a big 92-ml gulp, he or she would then have exactly 500 ml remaining in the cup. The customer would be shocked and dissatisfied when, after drinking only 92 ml, the cup disappeared from his or her hand and appeared in the sink, ready to be washed. And, even if the programmer making the change realized that you were using a special value, another special value for the unwashed attribute would have to be chosen.

A better approach to this situation is to have a separate field to model the separate attribute:

// In source packet in file fields/ex2/CoffeeCup.java
class CoffeeCup {

    private int innerCoffee;
    private boolean needsWashing;

    public boolean isReadyForNextUse() {

        // If coffee cup isn't washed, then it's
        // not ready for next use
        return !needsWashing;
    }

    public void setCustomerDone() {
        needsWashing = true;
        //...
    }

    public void wash() {
        needsWashing = false;
        //...
    }
    // ...
}

Here the innerCoffee field is used only to model the amount of coffee in the cup attribute. The cup-needs-washing attribute is modeled by the needsWashing field. This scheme is more easily understood than the previous scheme, which used a special value of innerCoffee and wouldn't prevent someone from expanding the maximum value for innerCoffee.

Page 1 of 7  >>

Design Techniques | Book List | Print | Email | First Page | Previous | Next

Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us