How to use Builder Pattern for designing method parameters

Details Written by Nam Ha Minh Last Updated on 02 July 2019 | Print Email

Do you write methods and theirs parameters in your daily coding?

Do you think you have problems in writing methods?

Have you ever applied good practices to design your method’s parameters?

1. Avoid writing a long list of parameters

public static void showMessageDialog(Component parentComponent, Object message, String title, int messageType, Icon icon)

JOptionPane

j avax.swing

2. Avoid writing a sequence of parameters of the same type

Insets

javax.swing

Insets(int top, int left, int bottom, int right)

Insets inset = new Insets(10, 5, 20, 15);

3. What if we cannot avoid a long list of parameters?

void drawString(String text, int x, int y, int fontSize, int fontStyle);

Technique #1: Break it into multiple methods

drawString()

void setFont(int fontSize, int fontStyle); void drawString(String text, int x, int y);

Increase the weight of the class (more methods).

It’s not always easy to break the method.

The client code is somewhat verbose when invoking multiple methods.

Technique #2: Create a helper class with JavaBean style

drawString()

TextObject

class TextObject { String text; int fontSize; int fontStyle; int x; int y; public void setText(String text) { this.text = text; } public String getText() { return this.text; } // other getters and setters go here… }

TextObject textObj = new TextObject(); textObj.setText("Java World"); textObj.setX(100); textObj.setY(200); textObj.setFontSize(18); textObj.setFontStyle(Font.BOLD);

drawString()

drawString(textObj);

The client code may be too wordy as using many setters.

The helper class is mutable, which is not good for being passed into the method (Effective Java, Item 39 - Make defensive copies when needed).

It’s difficult to validate all the parameters in one place since the setters are invoked separately.

4. Technique #3: Using the Builder pattern

public class Person { // required fields: private String name; private int age; // optional fields: private Date birthday; private String email; private String phone; private String address; private float weight; private float height; // getters and setters }

Person

name

age

public Person(String name, int age); public Person(String name, int age, Date birthday); public Person(String name, int age, Date birthday, String email); public Person(String name, int age, Date birthday, String email, String phone); …

First way: sing the full-parameter constructor:

Person me = new Person("Name", 31, new Date(), "nam@gmail.com", "0123456789", "Hanoi", 65, 172);

Second way: using setter methods:

Person me = new Person(); me.setName("Name"); me.setAge(31); me.setBirthday(new Date()); me.setEmail("nam@gmail.com"); me.setPhone("0123456789"); me.setAddress("Hanoi"); me.setWeight(65); me.setHeight(172);

Person

Builder

Builder

Person

public class Person { public static class Builder { } }

Person

Builder

public static class Builder { private String name; private int age; private Date birthday; private String email; private String phone; private String address; private float weight; private float height; public Builder(String name, int age) { this.name = name; this.age = age; } public Builder name(String name) { this.name = name; return this; } public Builder age(int age) { this.age = age; return this; } public Builder birthday(Date birthday) { this.birthday = birthday; return this; } public Builder email(String email) { this.email = email; return this; } public Builder phone(String phone) { this.phone = phone; return this; } public Builder address(String address) { this.address = address; return this; } public Builder weight(float weight) { this.weight = weight; return this; } public Builder height(float height) { this.height = height; return this; } public Person build() { return new Person(this); } }

public Builder address(String address) { this.address = address; return this; }

Builder

build()

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

Person

Person

private Person(Builder builder) { this.name = builder.name; this.email = builder.email; this.age = builder.age; this.birthday = builder.birthday; this.phone = builder.phone; this.address = builder.address; this.weight = builder.weight; this.name = builder.name; }

Person

build()

Person

public Person build() { if (name == null) { throw new IllegalArgumentException("Name cannot be null"); } return new Person(this); }

Person

Person me = new Person.Builder("Nam", 31) .email("nam@gmail.com") .address("Hanoi") .build();

Person

Person you = new Person.Builder("You", 27) .birthday(new Date()) .email("nam@gmail.com") .phone("0123456789") .address("Hanoi") .weight(62) .height(170) .build();

Person

Other Java Coding Tutorials:



About the Author: Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on





is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on Facebook and watch his Java videos you YouTube.

Add comment

This tutorial introduces the best practices in designing method parameters in which the Builder pattern is an ultimate solution.First, let me ask you some questions:So read on, as I’m going to share with you some cool techniques employed by the experts to write methods professionally. And you can do that, too.Well, I have read thein the book Effective Java , so I am eager to share what I have learned with you.You know, there are some rules that tell us how to implement methods wisely.Here’s such a method:This method is taken from theclass in thepackage. It has 5 parameters - good enough to make us difficult to remember which one is for what. Frankly, this method makes me confused most of the time when I use it, as I always have to double-check its Javadoc to ensure I passed the arguments correctly.Having said that, the best practice is writing as few parameters as possible. Having many parameters is bad.A method has more than 4 parameters is too much. This should be avoided.A method has two parameters is good.A method has only one parameter is the best.And a method has no parameter is ideal.Consider the following constructor of theclass in thepackage:And a usage like this:This kind of method is easy to make confusion. Because all the parameters are integer, I often run into trouble when specifying which one is the left, which one is the bottom, and so on. So I always have to look at the Javadoc to make sure.This is also prone to error because I can put wrong parameters and the code is still compiled. The problem can be realized only at runtime.For example, the following method must have 5 parameters:According to Joshua Bloch (the author of Effective Java ), there are 3 techniques to solve the problem of long parameters list.Themethod above can be broken into two methods like this:However, the drawbacks of this technique are:In this technique, we can wrap all the parameters into a helper class that has getters and setters following JavaBean standard. For example, we can wrap the parameters of themethod above into aclass:Then use the helper class as follows:Then pass this object into themethod:This solution is fairly good to solve the problem of long parameters list. However there are some disadvantages:This technique combines the previous two techniques with the builder pattern to solve the problem of long parameters list. Consider the following class:Thisclass has only two required fields:and, and the rest are optional.Besides the getters and setters, we tend to implement various constructors like these:and so on, until the last constructor covers all the fields, which is equivalent to 8 parameters. Ouch!Suppose that we want to create a new Person object with full details, we tend to use two ways:8 arguments to pass! Too much to remember which one is for which purpose. Such long list of parameters causes the code hard to read and maintain.This looks better than using the full-parameter constructor, however it is too wordy. Also theobject is mutable, which is not good to pass into the method.Now, let’s see how thepattern can solve the problems above.First, we create aclass which is nested inside theclass:Remember to remove all the setters of theclass.Here’s the detailed implementation of theclass:You see, this builder class has same fields as the enclosing class, but the methods for setting values are different. Take a look at this method:The interesting point here is that this method returns theitself. Why? It’s for easily chaining multiple invocations together. You will see how in the usage example below.The second interesting point is in themethod:Look, this method returns a new object of theclass. We need to make the’s constructor private like this:This is the sole constructor of theclass, it copies values of the fields from the builder to itself.In addition, we can add code to validate the fields in themethod before returning the newobject. For example:That’s done for the implementation of theclass’ builder. Now, let’s see how to use this pattern:Wow! This looks more readable than using a full-parameter constructor, right?Let’s see another usage which creates aobject with full details:You see? This is very flexible and easy to read, right? Theobject created is now immutable (remember to remove all its setters).This builder pattern solves the problems of long parameters list nicely. It takes more time to implement but it will pay off in the long term as the code evolves.So far I have focused on the implementation of the Builder pattern, for more good practices about methods, consult the Effective Java book.