Properties are named attributes or characteristics. They define the
behavior and state of an object. For instance, the current
temperature value of the Temperature
object is a
property, as are the high and low temperature thresholds of the
GenericTemperatureThresholdAdapter
from the
previous chapter. Properties are referenced by their name and can
have any type, including primitives such as int
,
and class and interface types such as
java.awt.Color
. The name of the low threshold
property is LowThreshold, and its type is
double
. Properties are usually part of the
persistent state of an object. This will be dealt with later in Chapter 5.
Properties are exposed to visual programming tools and scripting environments, as well as to traditional Java programming. They are manipulated in a visual programming tool through some kind of property-editing interface. In a scripting environment, properties are exposed through a field-style syntax such as Object.Property = value, and value = Object.Property. These are syntactical conveniences provided by the scripting environment. As a Beans developer, you’ll expose your properties as described in the rest of this chapter.
An object’s properties are accessed by calling methods that are defined for setting and getting the property value. Any property that can be read will have an associated method for getting its value. Likewise, any property that can be written will have an associated method for setting its value. We’ll see shortly that objects don’t always provide both access mechanisms for every property. Properties can be read/write, read-only, or write-only.
The methods used for getting and setting property values should conform to the standard design pattern for properties. These methods are allowed (but not required) to throw checked exceptions. The method signatures are as follows:
public void set<PropertyName>(<PropertyType> value); public <PropertyType> get<PropertyName>();
The existence of a matching pair of
methods that conform to this pattern represents a read/write property
with the name <PropertyName>
of the type
<PropertyType>
. If only the
get()
method exists, the property is considered to
be read-only; if only the set()
method exists, the
property is considered to be write-only.
If the <PropertyType>
is
boolean
, the get()
method can
be replaced or augmented with a method that uses the following
signature:
public boolean is<PropertyName>();
Let’s look back at the Temperature
class.
The current temperature is stored within an object of type
Temperature
, but up until now we have not provided
a way to access that value. So now we can add a read-only property
called CurrentTemperature. The code for the
Temperature
class will now include the following:
package BeansBook.Simulator;
import java.util.Vector;
public class Temperature
{
// the current temperature in Celsius
protected double currentTemp = 22.2;
[The rest of the existing code goes here]
// the get method for property CurrentTemperature
public double getCurrentTemperature()
{
return currentTemp;
}
}
It is important to recognize that properties are not defined by data
members of the object’s class. One reason for this is that it
would break encapsulation. More importantly, properties can be
computed when they are needed without having to be stored explicitly.
In an earlier example we described a Thermometer
class that tracked temperatures from two locations. We could define a
property called NumberOfLocations. This is a
read-only property that describes how many locations are being
tracked by the thermometer. In this case we don’t need to
explicitly store a data member for this property, we just know that
the value is always 2. We could add a property get method to access
this value, as follows:
public int getNumberOfLocations() { return 2: }
Although our thermometer isn’t a visual component yet, imagine
that at some point it will be capable of displaying the temperature
from one of its source thermometers. Let’s design the
Thermometer
so that it is capable of displaying
temperatures in either Celsius or Fahrenheit. We call this property
DisplayingCelsius, and we expose it using a
boolean
data type. Remember that this
doesn’t refer to the way that the property is stored
internally, only the way that the property is exposed externally. If
Celsius is not used, then Fahrenheit is being used, and vice versa.
We’ll put off implementing the property until later. So the
code for the Thermometer
class now looks like
this:
package BeansBook.Simulator; public class Thermometer implements TempChangeListener { // a reference to the temperature object that we are monitoring protected Temperature theTemperature; Thermometer(Temperature temperature) { theTemperature = temperature; // register for temperature change events theTemperature.addTempChangeListener(this); } // handle the temperature change events public void tempChanged(TempChangedEvent evt) { // do something with the temperature that we can retrieve // by calling evt.getTemperature() } // the get method for the DisplayingCelsius property public boolean isDisplayingCelsius() { ... } // an alternate get method for the DisplayingCelsius property public boolean getDisplayingCelsius() { return isDisplayingCelsius(); } // the set method for the DisplayingCelsius property public void setDisplayingCelsius(boolean value) { ... } }
In this example I’ve provided both forms of the get method for
the boolean
property
DisplayingCelsius. You’ll notice that the
only method that has an implementation so far is
getDisplayingCelsius()
, which does nothing but
call the isDisplayingCelsius()
method. We’ll
fill in the code later.
Tip
Whenever two methods are provided that perform the same function, it is a good idea to implement one in terms of the other. There is no requirement to do this, but it is a good programming practice. Following this guideline will eliminate the need to repeat code, and to modify multiple areas of code when the implementation changes.
Normally when a property value is changed, the object will react in
some way. Later, when our Thermometer
object is
capable of displaying a temperature value, we will have to implement
code that reacts to a change to the
DisplayingCelsius property by redisplaying the
temperature according to the temperature units being used (Celsius or
Fahrenheit).
Get Developing Java Beans now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.