Archive for the ‘design patterns’ Category

Recently I was doing code review on my current project and I came across this class and it resulted in this post.

 

This code is harder for clients. Which constructor should I invoke as a client? The one with 2 parameters? The one with 3? What is the default value for those parameters where I don’t pass an explicit value? What if I want to set a value for address but not for age and phone? In that case I would have to call the constructor that takes all the parameters and pass default values for those that I don’t care about. Additionally, several parameters with the same type can be confusing. Was the first String the name or the value?

The alternate approach we have is to have a default no-arg constructor and have setters and getters for every attribute. As a client I can just create an empty object and then set only the attributes that I’m interested in. But this will leave the class in an inconsistent state. If you want to create an WidgetPropertyVO object with values for all its 5 attributes then the object will not have a complete state until all the setter methods have been invoked. This means that some part of the client application might see this object and assume that is already constructed while that’s actually not the case.

So the final and best approach for such situations is the Builder Pattern .

I really like the Builder pattern for constructing objects when I have a lot of parameters, especially if many of these parameters are null and when many of them share the same data type.

So lets re-write this class and see how it looks like after using Builder Pattern.

Step 1: So we will remove all the constructors from the previous implementation. and we will only retain all the previous attributes and their getter-setter methods.

 

 

Step 2:  We need to create a static nested class and then copy all the arguments from the outer class to the Builder class. We should follow the naming convention and if the class name is WidgetPropertyVOthen builder class should be named as WidgetPropertyVOBuilder.

Builder class should have a public constructor with all the required attributes as parameters.

Builder class should have methods to set the optional parameters and it should return the same Builder object after setting the optional attribute.

The final step is to provide a build() method in the builder class that will return the Object needed by client program. For this we need to have a private constructor in the Class with Builder class as argument.

 

Lets try to create an object of WidgetPropertyVO now.

WidgetPropertyVO widgetPropertyVO = new WidgetPropertyVO.WidgetPropertVOBuilder(“Task Widget”, “10”).fieldPos(10).build();

 

The benefit of builder pattern is that its easy to write and read the code and makes the class immutable but the criticism is that you have to duplicate the class’ attributes on the builder. However, given the fact that the builder class is usually a static member class of the class it builds, they can evolve together fairly easy.

 

Please find below the sample class.

public class WidgetPropertyVO {

private String name;
private Object value;
private List taskList;
private boolean required;
private int fieldPos;

private WidgetPropertyVO(WidgetPropertVOBuilder builder) {
this.name = builder.name;
this.value = builder.value;
this.required = builder.required;
this.fieldPos = builder.fieldPos;
this.taskList = builder.taskList;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Object getValue() {
return value;
}

public void setValue(Object value) {
this.value = value;
}

public List getTaskList() {
return taskList;
}

public void setTaskList(List taskList) {
this.taskList = taskList;
}

public boolean isRequired() {
return required;
}

public void setRequired(boolean required) {
this.required = required;
}

public int getFieldPos() {
return fieldPos;
}

public void setFieldPos(int fieldPos) {
this.fieldPos = fieldPos;
}

public static class WidgetPropertVOBuilder {
private final String name;
private final Object value;
private List taskList;
private boolean required;
private int fieldPos;

public WidgetPropertVOBuilder(String name, Object value) {
this.name = name;
this.value = value;
}

public WidgetPropertVOBuilder fieldPos(int fieldPos) {
this.fieldPos = fieldPos;
return this;
}

public WidgetPropertVOBuilder required(boolean required) {
this.required = required;
return this;

}

public WidgetPropertVOBuilder taskList(List taskList) {
this.taskList = taskList;
return this;
}

public WidgetPropertyVO build() {
return new WidgetPropertyVO(this);
}

}

}

Advertisements