The main goal of the article is to make you remember 2 things:
- Constructors aren’t like cheese, i.e., they don’t get better with age
- An “ad litteram” iterative approach on writing constructors is BAD
How bad you wonder? Well… this bad:
new Admin(code,
name,
propId,
locale,
description,
serviceNo,
emailAddress1,
emailAddress2,
rfiEmailAddress,
generalReports,
vatNumber,
partnerId,
junk,
dateJoining,
appSessionId,
legalType,
legalTypeOther,
contractRelationshipId,
keyAccountTypeId,
crmId,
virtualTerminal,
acquirerCountryConfirmed,
acquirerUsesRegistration,
sanction,
timestamp,
passwordExpiryDays,
concurrentLogins,
nonUseSuspensionDays,
contractVersionId,
calculateVAT,
version);
Usually, when you add a new field to an existing class, usually domain model classes, you have 2 options:
- Enhance the existing constructor by adding a parameter. But this will affect all the existing code. Do you really want to break existing integration?
- The “Telescopic way”: create a new constructor that has just one more parameter that delegates the initial parameters to the initial constructor. This won’t affect existing integration, but, in time it will lead to very hard to read code – sample above.
Of course, there are patterns to solve this. You may go for the static
factory method way, but, again you may end up in a similar situation:
BankAccountFactory.create(
null,
number,
null,
"SWEDEN",
null,
null,
null,
null,
null,
accountHolderName,
accountHolderResidence,
null,
"EUR",
null,
null,
null);
Don’t worry, there are better patterns. The best I recommend is the Builder pattern presented by Joshua Bloch in Effective Java. More details can be found here. And it also uses to some extent the Fluent Interface pattern presented by Martin Fowler in this post. This pattern is very powerful because it allows you to enforce consistency for your objects. Well … this is not exactly quite true as you can still supply null/invalid values to the constructor. That’s why I’m proposing a lighter alternative by getting rid of the actual Builder which duplicates code a little with the downside of losing that formal enforced consistency. So the code will look like this:
public class Account {
private String id;
private String owner;
private String accountNumber;
private Date expiryDate;
private int level;
public static Account _new() {
return new Account();
}
public Account id(String theId) {
this.id = theId;
return this;
}
public Account owner(String own) {
this.owner = own;
return this;
}
public Account accountNumber(String an) {
this.accountNumber = an;
return this;
}
public Account expiryDate(Date date) {
this.expiryDate = date;
return this;
}
public Account level(int lev) {
this.level = lev;
return this;
}
public String id() {
return this.id;
}
public String owner() {
return this.owner;
}
public static void main(String... args) {
Account ac = Account._new().id("20").accountNumber("ABCDEF")
.owner("me").expiryDate(new Date()).level(4);
}
}
What do you think?
Filed under: Best Practices, CodeProject, Design Patterns
Tagged: builder, constructor, design pattern, fluent interface