Effective Java tip no 2

Effective Java Notes:  CONSIDER A BUILDER WHEN FACED WITH MANY CONSTRUCTOR PARAMETERS

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

  1. Parameters of same type might be swapped. There will be no compilation errors but there will be a problem in the expected output.
  2. Unnecessary initialization of fields. 
  3. 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:

  1. 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. 
  2. 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:

  1. It is easier to read and write
  2. Support for multiple varags
  3. The Builder pattern is flexible. A single builder can be used to build multiple objects.
  4. A builder whose parameters have been set makes a fine Abstract Factory

0 comments: