Constructors in general
Constructors:
Note that a conventional distinction is made in Java between the
"default constructor"
and a "no-argument constructor":
-
the default constructor is the constructor provided by the system in the
absence of any constructor provided by the programmer. Once a programmer
supplies any constructor whatsoever, the default constructor is no longer
supplied.
-
a no-argument constructor, on the other hand, is a constructor provided
by the programmer which takes no arguments.
This distinction is necessary because the behavior of the two kinds of constructor are
unrelated: a default constructor has a fixed behavior defined by Java, while the
behavior of a no-argument constructor is defined by the application programmer.
Example
Resto
is an immutable class, since
its state cannot change after construction. Note that:
-
all validation is performed in its constructor
-
almost all of its javadoc is concerned with stating precisely what is to
be passed to the constructor
package hirondelle.fish.main.resto;
import hirondelle.web4j.model.ModelCtorException;
import hirondelle.web4j.model.ModelUtil;
import hirondelle.web4j.model.Id;
import hirondelle.web4j.security.SafeText;
import hirondelle.web4j.model.Decimal;
import static hirondelle.web4j.model.Decimal.ZERO;
import hirondelle.web4j.model.Check;
import hirondelle.web4j.model.Validator;
import static hirondelle.web4j.util.Consts.FAILS;
public final class Resto {
public Resto(
Id aId, SafeText aName, SafeText aLocation, Decimal aPrice, SafeText aComment
) throws ModelCtorException {
fId = aId;
fName = aName;
fLocation = aLocation;
fPrice = aPrice;
fComment = aComment;
validateState();
}
public Id getId() { return fId; }
public SafeText getName() { return fName; }
public SafeText getLocation() { return fLocation; }
public Decimal getPrice() { return fPrice; }
public SafeText getComment() { return fComment; }
@Override public String toString(){
return ModelUtil.toStringFor(this);
}
@Override public boolean equals(Object aThat){
Boolean result = ModelUtil.quickEquals(this, aThat);
if (result == null) {
Resto that = (Resto) aThat;
result = ModelUtil.equalsFor(
this.getSignificantFields(), that.getSignificantFields()
);
}
return result;
}
@Override public int hashCode(){
if (fHashCode == 0){
fHashCode = ModelUtil.hashCodeFor(getSignificantFields());
}
return fHashCode;
}
private final Id fId;
private final SafeText fName;
private final SafeText fLocation;
private final Decimal fPrice;
private final SafeText fComment;
private int fHashCode;
private static final Decimal HUNDRED = Decimal.from("100");
private void validateState() throws ModelCtorException {
ModelCtorException ex = new ModelCtorException();
if (FAILS == Check.optional(fId, Check.range(1,50))) {
ex.add("Id is optional, 1..50 chars.");
}
if (FAILS == Check.required(fName, Check.range(2,50))) {
ex.add("Restaurant Name is required, 2..50 chars.");
}
if (FAILS == Check.optional(fLocation, Check.range(2,50))) {
ex.add("Location is optional, 2..50 chars.");
}
Validator[] priceChecks = {Check.range(ZERO, HUNDRED), Check.numDecimalsAlways(2)};
if (FAILS == Check.optional(fPrice, priceChecks)) {
ex.add("Price is optional, 0.00 to 100.00.");
}
if (FAILS == Check.optional(fComment, Check.range(2,50))) {
ex.add("Comment is optional, 2..50 chars.");
}
if ( ! ex.isEmpty() ) throw ex;
}
private Object[] getSignificantFields(){
return new Object[] {fName, fLocation, fPrice, fComment};
}
}
See Also :