private Collection< String > values_;
public Collection< String > getValues() {
return (
null == this.values_
? this.values_ = new ArrayList<>()
: this.values_
);
}
public void setValues( Collection< String > values ) {
this.values_ = values;
}
Nowadays you can find a lot of code like this in places like JAXB generated code, etc. Where you want the consumer of the class to be able to start doing stuff like:
Wizzle wuzzle = new Wizzle();
wuzzle.getValues().add( "ok" );
But there are a few problems with this. For one thing it assumes that there is no value to having the getValues call return null. Which impacts code like:
int sum = 0;
int count = 0;
for ( Wizzle wuzzle : wuzzles ) {
if( null != wuzzle.getValues() ) {
sum += wuzzle.getValues().size;
count++;
}
}
if ( 0 != count ) {
System.out.println(
"average is "
+ ( sum / ( double ) count )
);
}
Of course, I also suddenly have created a bunch of ArrayLists I really don't need.
Now you might say: so what? And OK, but the fact is, a collection being unset (ie: null) is used in a fair number of places to perform logic or calculations.
Notice how the coolio automagic collection trick throws off my averages in this code that assumes null == wuzzle.getValues() mean "undefined."
Now I am writing (ok, generating) code like this instead:
private Collection< String > values_;
public Collection< String > getValues() {
return (
this.valuesUnSet()
? this.setNewValues()
: this.values_
);
}
public boolean valuesUnSet() {
return ( null == this.values_ );
}
protected Collection< String > setNewValues() {
return ( this.values_ = this.newValues() );
}
public Collection< String > newValues() {
return new ArrayList< String >();
}
public void setValues( Collection< String > values ) {
this.values_ = values;
}
But in order for this to really work, the code to do the average has to be changed to:
int sum = 0;
int count = 0;
for ( Wizzle wuzzle : Wuzzles ) {
if( !wuzzle.valuesUnSet() ) {
sum += wuzzle.getValues().size;
count++;
}
}
if ( 0 != count ) {
System.out.println(
"average is "
+ ( sum / ( double ) count )
);
}
The nice thing about this refactored code is that it doesn't make the assumption that "null" for a collection means uninitialized.
Instead the decision as to whether or not the Collection has been initialized is left up to the model object's implementation.
This approach removes a potentially dangerous assumption while allow automagic collections to be used without penalty.
It is a small incremental improvement on the basic design.
No comments:
Post a Comment