Back to Thoughts On Technology Page | Back to Peter's Home Page | Back to Family Home Page



Effective Use of Java Object Constructors
Peter Rose - 01/2005


ABSTRACT

SUMMARY

DIFFERENT APPROACHES TO USING THE CONSTRUCTOR

PROBLEMS WITH PROPERTY INITIALIZATION VIA THE CONSTRUCTOR

OTHER PROBLEMS

USING CONSTRUCTORS TO PROVIDE INITIAL OBJECT STATE

THE DTO ISSUE

AVOIDING PROBLEMS WITH OBJECT INSTANCE PROPERTIES





Abstract
There are several ways of using a constructor to instantiate an object. Some are good and some not so good. I'll discuss the pros and cons of each mostly as to how each could ultimately affect overall system maintenance.

Summary
Objects can be instantiated with constructors that are empty, pass parameters to initialize object properties, or pass object parameters that create some form of state for the new object.

This article shows why it is not a good idea to pass parameters to a constructor that are to initialize object properties

Different Approaches To Using The Constructor
A constructor allows us to instantiate and obtain a handle to an object. It also enables us to initialize state properties on an object at instantiation. For example, if I am instantiating an engine monitoring object, I may want to pass it a handle to the engine object that it is to monitor:


EngineMonitor monitor = new EngineMonitor( engine );

whereas the engine object itself would have previously been instantiated and various properties of it set via accessor methods as follows:


Engine engine = new Engine();
engine.setFuelIntake( true );
engine.setAirMix( determinedMixLevel );
engine.setFilterFlow ( FilterFlow.START_UP);

Problems With Property Initialization Via The Constructor
Though it would be possible to instantiate the engine object and set its properties via the constructor in this manner


Engine engine = new Engine(
		true,
		determinedMixLevel,
		FilterFlow.START_UP);

this is not the most efficient, understandable, extensible, or maintainable form of construction. As improvements to engine technology take place, additional properties will be added to the class that will need setting. The maintenance programmer must then find all instances of instantiation to add the new parameters. Most likely in the constructor's setter methods for those new properties there will have to be additional conditional coding added to determine if the setting should be applied immediately or later.

Other Problems
There are other issues as well. Multiple parameters with the same data type can become confusing as to which parameter belongs with which value. Good method construction theory indicates keeping the number of parameters to 3 or less and that those parameters when at all possible should be objects rather than raw data types. A constructor is just another form of method and so should follow the same base rules for methods.

The problem with initializing object properties with constructor parameters is that as the system changes the responsibilities and duties of the object will change as well. It is much more straight forward to use setter methods after instantiating the object. In this way, better control over the initialization of object parameters is had and makes for a much cleaner api interface. Older parts of the program where the object is used may not need the setting of the new properties. Having to adjust the constructor in those places could be confusing to a new team member.

A possible way around this would be to create multiple constructors - putting the new parameters into the overloaded constructor. But what happens when another parameter needs to be added? Do you create another constructor? How many overloaded constructors is too many? Even having 3 constructors with similar signatures is too confusing. All of that is avoided by simple use of accessors for all object property initialization.

A perhaps equally confusing solution would be to limit constructor initialization to 3 overridings and then use accessors. There would be little organization or logic to such an implementation. Maintenance of such an object under these differing methods of initialization would be problematic.

Using Constructors To Provide Initial Object State
In the case of the EngineMonitor instantiation, however, the intent was not to initialize the properties of the EngineMonitor, but rather to provide state for it. The engine object and engineMonitor object are really two different types of objects. The engineMonitor object is a service class whereas the engine object is a JavaBean object - specifically a session bean. And in general, service classes tend not to have raw data type instance properties that depend on external setting anyway.

These types of objects - by strict definition of the Object Model - must have both properties and service methods, and they must communicate via messaging with other objects in the system ensuring high encapsulation and loose coupling. Both the EngineMonitor and Engine objects satisfy these requirements, however, they go about it with different purposes.

The EngineMonitor object provides services for the Engine object that the Engine object should not need to know about. For example, the engine should know how to process the fuel that it is given but it should not have to know the level of its fuel tank - that would be the job of the EngineMonitor class. However, the Engine class's aggregate object FuelTank is neither a service class nor is it a session bean. FuelTank is an entity bean, i.e. a bean that could be either serialized or persisted to a data store. To initialize it's properties, the use of accessors over constructors keeps the overall api of objects in the system consistent.

The DTO Issue
This would be true as well for another type of object similar to an entity bean: the DTO or Data Transfer Object. These objects generally contain the properties of many objects. They are populated from a screen form submission or a complex database query, for example. They characteristically do not have any service methods on them; they are used only as a temporary store of dissimilar data which other service objects extract (usually directly as public properties vs. accessors) and distribute to a graph of other objects (both service and session beans) used in the system. In fact, some current thought in regard to DTO type objects is to make all properties public and not have accessors at all; the object is short lived anyway so what is the purpose of data hiding?

Thus, depending on the type of object and how it is to be used in the system determines whether use of the constructor as an initializer of object properties might be appropriate. In general, initializing object properties via the constructor is not recommended. However, using the constructor to initialize some type of object state may be very appropriate. This type of initialization tends to be done with one or at most two objects and will not change even as the object mutates through time.

Avoiding Problems With Object Instance Properties
In a related matter to constructor initialization of class instance properties are the property definitions themselves. All class property definitions should include an initial value and definitions of the following format should be avoided:


String prop1;
String prop2;
int prop3;
List propList;
EngineMonitor engineMonitor;

Rather, each property should be given an initial value such as:


String prop1 = "";
String prop2 = "";
int prop3 = 0;
List propList = new ArrayList();
EngineMonitor engineMonitor = new EngineMonitor();

In this way, random and unexpected NullPointerExceptions can be avoided and a lot of unnecessary Exception checking code can be eliminated.

Of course, this means that business process flow cannot be dependant on null values. But it is just as easy to have the business process conditional be based on an empty value. And possibly, the fact that the object/value is empty is just reflected in an empty screen display -avoiding the need to check for the condition.


Back to Thoughts On Technology Page | Back to Peter's Home Page | Back to Family Home Page