Constructors in general
Constructors :
- if super or this are called, they can only be called on the first line of the constructor
- an Exception can be thrown if a parameter is invalid
- you should ensure that the constructed object is in a valid state
- constructors should never call an overridable method (an overridable method is one which is neither private, static, nor final)
- constructors are never synchronized
- constructors can create thread objects, but the thread should not be started within a constructor
- constructors shouldn't let the this reference escape
- constructors can be private, in order to restrict construction
- 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.
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; /** Model Object for a Restaurant. */ public final class Resto { /** Full constructor. @param aId underlying database internal identifier (optional) 1..50 characters @param aName of the restaurant (required), 2..50 characters @param aLocation street address of the restaurant (optional), 2..50 characters @param aPrice of the fish and chips meal (optional) $0.00..$100.00 @param aComment on the restaurant in general (optional) 2..50 characters */ 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 // 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 :
Validate method arguments
Validate state with class invariants
Initializing fields to 0-false-null is redundant
Immutable objects
Private constructor
Avoid JavaBeans style of construction
Constructors shouldn't call overridables
Don't let this reference escape
Constructors shouldn't start threads
Validate state with class invariants
Initializing fields to 0-false-null is redundant
Immutable objects
Private constructor
Avoid JavaBeans style of construction
Constructors shouldn't call overridables
Don't let this reference escape
Constructors shouldn't start threads
Would you use this technique?
|
|