The scope and lifetime of a field is the same as the object to which it is attached. Because the primary allegiance of fields is to the object as a whole, declare fields together either at the beginning or end of the class. At the beginning, the declarations give a reader important context to use while reading the rest of the code. Leaving the declarations until last sends the message, “Behavior is king; data is an implementation detail.” While I agree philosophically with the statement that logic is more important than data in object programs, I still like to read the declarations first, wherever they are, when I am reading code.
One of your options with a field is to declare it final. This tells readers that the value of the field will not change after the constructor has run. While I mentally keep track of which of my fields are final and which are not, I don’t declare fields explicitly. The extra clarity is not worth the extra complexity for me, but if I were writing code that would be changed by many people over a long time, it seems worth making the distinction between final and volatile fields explicit.
The list of roles for fields is not as comprehensive as the list for local variables. However, here are a few common roles for fields:
Helper: helper fields hold references to objects used by many of an object’s methods. If an object is passed as a parameter to many methods, consider replacing the parameter with a helper field set in the complete constructor.
Flag: boolean flag fields say, “This object can act in two different ways.” If there is a setter method for the flag, it additionally says, “… and the behavior can change during the life of the object.” Flag fields are fine if they are only used in a few conditionals. If the code making decisions on the basis of the flag is duplicated, consider changing to a strategy field instead.
Strategy: when you want to express that there are alternative ways to perform some part of an object’s computation, store in a field an object performing just the variable part of the computation. If this variation in behavior doesn’t change during an object’s lifetime, set the strategy field in the complete constructor. Otherwise, provide methods for changing it.
State: state fields are like strategy fields in that part of the behavior of the object is delegated to them. However, state fields, when triggered, set the following state themselves. Strategy fields are changed, if at all, by other objects. State machines implemented this way can be difficult to read, since the states and transitions are not expressed in one place. However, for simple state machines they can suffice.
Components: these fields hold objects or data “owned” by the referring object.
|This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License|