Constructors with large number of optional parameters do not scale too well.
Consider the following class
class Appointment {
String appointmentTitle; //Mandatory
Date appointmentStartTime; //Mandatory
Date appointmentEndTime; //Optional
ArrayList < Contact > invitedPeople; //Optional
String description; //Optional
ArrayList < Task > toDoList; //Optional
////////Constructor with two parameters
public Appointment(String appointmentTitle, Date appointmentStartTime) {
...
}
///////Constructor with all the parameters
public Appointment(String appointmentTitle, Date appointmentStartTime, Date appointmentEndTime, ArrayList < Contact > invitedPeople, String description,
ArrayList < Task > toDoList) {
....
}
}
Problems with this approach
- Parameters of same type might be swapped. There will be no compilation errors but there will be a problem in the expected output.
- Unnecessary initialization of fields.
- The telescoping constructor pattern works, but it is hard to write client code when there are many parameters, and harder still to read it. The reader is left wondering what all those values mean and must carefully count parameters to find out.[Quote from Effective java]
Alternative 1: Using Java beans with setter methods and default constructor
Problems with this approach:
- Because construction is split across multiple calls, a JavaBean may be in an inconsistent state partway through its construction. The class does not have the option of enforcing consistency merely by checking the validity of the constructor parameters. Attempting to use an object when it’s in an inconsistent state may cause failures that are far removed from the code containing the bug, hence difficult to debug.
- A related disadvantage is that the JavaBeans pattern precludes the possibility of making a class immutable, and requires added effort on the part of the programmer to ensure thread safety.[Quote from Effective java]
Alternative 2: Using Builder
public class Appointment {
String appointmentTitle; //Mandatory
Date appointmentStartTime; //Mandatory
Date appointmentEndTime; //Optional
ArrayList < Contact > invitedPeople; //Optional
String description; //Optional
ArrayList < Task > toDoList; //Optional
private Appointment(Builder builder) {
appointmentTitle = builder.appointmentTitle; //Mandatory
appointmentStartTime = builder.appointmentStartTime; //Mandatory
appointmentEndTime = builder.appointmentEndTime; //Optional
invitedPeople = builder.invitedPeople; //Optional
description = builder.description; //Optional
toDoList = builder.toDoList; //Optional
}
public static class Builder {
String appointmentTitle; //Mandatory
Date appointmentStartTime; //Mandatory
Date appointmentEndTime; //Optional
ArrayList < Contact > invitedPeople; //Optional
String description; //Optional
ArrayList < Task > toDoList; //Optional
public Builder(String appointmentTitle, Date appointmentStartTime) {
this.appointmentTitle = appointmentTitle;
this.appointmentStartTime = appointmentStartTime;
}
public Builder appointmentEndTime(Date val) {
appointmentEndTime = val;
return this;
}
public Builder invitedPeople(ArrayList < Contact > val) {
invitedPeople = val;
return this;
}
public Builder description(String val) {
description = val;
return this;
}
public Builder toDoList(ArrayList < Task > val) {
toDoList = val;
return this;
}
public Appointment build() {
return new Appointment(this);
}
}
}
Then you can create an Appointment Object like
Appointment appt=new Appointment.Builder("Meeting", startTime).appointmentEndTime(endTime).description("Description").invitedPeople(invitedPeople).toDoList(list).build();
Advantages of this method:
- It is easier to read and write
- Support for multiple varags
- The Builder pattern is flexible. A single builder can be used to build multiple objects.
- A builder whose parameters have been set makes a fine Abstract Factory
0 comments:
Post a Comment