Lesson 5 | Property design patterns |
Objective | How do you define and use "Property Design Patterns"? |
How do you define and use "Property Design Patterns"?
Property design patterns are used to identify the properties of a Bean. Not surprisingly, property design patterns are closely related to accessor methods. In fact, accessor methods are the means by which the JavaBean's automatic introspection facility determines the properties of a Bean.
Basically, any time the JavaBeans introspector encounters a public getter or setter method, it assumes the member variable being get or set is a property, and then exposes the property to the outside world.
Types of property design patterns
What are Boolean Property Design Patterns?
Although they technically are simple properties, boolean properties have an optional design pattern for the getter method that can be used to make it more clear that the property is boolean. The design pattern for the boolean getter method follows:
public boolean isPropertyName();
The only difference between this design pattern and the one for simple properties is that it uses the word is instead of
get in the method name.
Following is an example of a pair of accessor methods for a boolean property named
visible:
public boolean isVisible();
public void setVisible(boolean v);
You might be curious as to what happens if both a
get method and an
is method are defined for a boolean property.
JavaBeans handles this potentially confusing situation by always using the
is method if it is available, and the
get method if not.
Boolean Properties
In addition, for boolean properties, we allow a getter method to match the pattern: public boolean is <PropertyName>();
This
is<PropertyName>
method may be provided instead of a
get<PropertyName>
method,
or it may be provided in addition to a
get<PropertyName>
method.
In either case, if the
is<PropertyName>
method is present for a boolean property then we will
use the
is<PropertyName>
method to read the property value.
An example boolean property might be:
public boolean isMarsupial();
public void setMarsupial(boolean m);
Indexed Properties
If we find a property whose type is an array
<PropertyElement>[]
, then we also look for methods of the form:
public <PropertyElement> get<PropertyName> (int a);
public void set<PropertyName>(int a, <PropertyElement> b);
If we find either kind of pattern then we assume that >propertyName> is an indexed property and that these methods can be used to read and/or write an indexed value. Thus an indexed property "foo" might be represented by four accessor methods:
public Bah[] getFoo();
public void setFoo(Bah a[]);
public Bah getFoo(int a);
public void setFoo(int a, Bah b);
Design Patterns for Events
By default, we use the following design pattern to determine which events a bean multicasts. We look for a pair of methods of the form:
public void add <EventListenerType>(<EventListenerType> a)
public void remove <EventListenerType>(<EventListenerType> a)
where both methods take the same
<EventListenerTyp>
type argument, where the <EventListenerType type> extends the
java.util.EventListener
interface, where the first method starts with
add, the second method starts with
remove
,
and where the <EventListenerType> type name ends with
Listener
.
This design pattern assumes that the Java Bean is acting as a multicast event source for the events specified in the <EventListenerType> interface.
So for example:
public void addFredListener(FredListener t);
public void removeFredListener(FredListener t);
defines a multicast event source.
The design patterns for properties vary a little based on the type of property. Following are the different property design patterns:
- Simple property design patterns
- Indexed property design patterns
At first glance it appears that you will have to implement the entire java.beans.BeanInfo interface even if you have a very simple Bean that only requires a few of the different descriptors. Actually, each of the methods in the interface are free to return null, indicating that the caller should use low-level reflection to gather the information. To make it easier to implement simple BeanInfo classes, the class java.beans.SimpleBeanInfo
implements all of the interfaces of the java.beans.BeanInfo interface.
Each method denies any knowledge of the associated data, suggesting that reflection should be used. You can derive your own BeanInfo classes by extending java.beans.SimpleBeanInfo, overriding those methods that return the information that you want to explicitly specify.
Another important aspect of providing explicit introspection information is information about base classes. If low-level reflection is used to analyze a Bean, all of its base classes (superclasses) are also analyzed by walking upwards through the class hierarchy. Each base class is analyzed in turn. The information gathered while analyzing a particular class is considered to be definitive. This means that if property information is found in a base class and that has already been discovered in a subclass, the subclass information takes precedence. For example, let's say class A has a read-only property called Value, and class B extends class A and implements the public methods getValue() and setValue(). The information in class B takes precedence over the information in class A, so any Bean based on class B will have a read/write property called Value, while the Value property of a Bean based on class A will be read-only.
JavaBeans Quiz Question
Which of the given options contain the correct set of methods for getting and setting the value of a boolean property 'bright', according to JavaBeans naming standards?
Select two choices.
a. public void setBright(boolean bright)
public boolean getBright()
b. public void setBright(boolean bright)
public boolean isBright()
c. public void setbright(boolean bright)
public boolean getbright()
d. public void setbright(boolean bright)
public boolean isbright()
Answer: a, b
Explanation:
Choices A and B are the correct answers. According to the JavaBeans naming standards, if the property name is 'x' and the type is Type,
the accessor method is of the form:
Type getX()
and the mutator method is of the form:
void setX(Type newValue)
However, boolean property also uses another convention:
boolean isX()
void setX(boolean newValue)
So choice C is incorrect, while choices A and B are correct. The name of the property is capitalized in the accessor and mutator methods.
So choice D is incorrect.
Property Design - Exercise
Click the Exercise link to define accessor methods based on property design patterns.
Property Design - Exercise
In the next lesson,
multicast event design patterns will be discussed.