Trying out generics, I made a generic value object with JDK 1.5:
/**
* <code>ObjectValueBase</code> is the abstract base for simple comparable,
* value types.
*
* @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
* @version $Revision$
* @since 1.0
*/
abstract class ObjectValueBase <T extends Comparable<T>, V extends ObjectValueBase<T, V>>
implements Cloneable, Comparable<V> {
private T value;
/**
* Constructs a new <code>ObjectValueBase</code> with the given
* <var>value</var>.
*
* @param value the value
*
* @throws IllegalArgumentException if <var>value</var> is invalid
*/
protected ObjectValueBase(final T value) {
if (!valid(value))
throw new IllegalArgumentException();
this.value = value;
}
/**
* Gets the value of this value object.
*
* @return the value
*/
public T getValue() {
return value;
}
/**
* Validates that the given <var>value</var> is permitted for this
* <code>ObjectValueBase</code>. Constructors validate input this way. By
* default, all inputs are valid; subclasses should override to restrict
* input.
*
* @param value the value
*/
protected abstract boolean valid(final T value);
// Cloneable
/**
* {@inheritDoc}
*
* A typical implementation for class <code>Foo</code> which extends
* <code>ObjectValueBase</code> is: <pre> public Foo clone() {
* return new Foo(getValue());
* }</pre>
*/
@Override public abstract V clone();
// Comparable
/**
* {@inheritDoc}
*/
public int compareTo(final V that) {
if (null == that)
return -1;
else if (null == getValue())
return null == that.getValue() ? 0 : -1;
else
return getValue().compareTo(that.getValue());
}
// Object
/**
* After self and nullity tests, passes check for equality to the held
* value.
*
* {@inheritDoc}
*/
@Override public boolean equals(final Object o) {
if (this == o)
return true;
else if (!(o instanceof ObjectValueBase))
return false;
else // pass equality test on to value, even for different types
return equals((V) o);
}
private boolean equals(final V that) {
if (null == that)
return false;
else if (null == getValue())
return null == that.getValue();
else
return getValue().equals(that.getValue());
}
/**
* {@inheritDoc}
*/
@Override public int hashCode() {
if (null == getValue())
return 0;
else
return getValue().hashCode();
}
/**
* {@inheritDoc}
*/
@Override public String toString() {
if (null == getValue())
return null;
else
return getValue().toString();
}
}
The chief drawback, however, is that Java generics do not support native primitives, unlike templates in C++ or generics in all-object languages such as Scheme. And most value objects I use wrap primitives such as int
(any sort of small-scale numeric) or float
(often money). So I copy the class, take out the generics, and fix the wrapped type to be the needed primitive. A lot like JDK 1.4, then, but at least I get covariant return types for clone()
.
UPDATED: I added the C++-trick of including a class as a template parameter of its base class. In this case, by including the class as a generic parameter to ObjectValueBase
, I can specify that clone()
returns the correct type, no casts required. Neato!