Simplify Object Creation

From IntelliJ-Wiki

Jump to: navigation, search

Have you ever found yourself in a situation where you've been growing your class, adding more and more constructor parameters? Have you ever wished that you could take out the object creation code into a separate class and reorganize it to be more readable?

Let's take a look at a sample class with several chaining constructors. All these constructors are used somewhere in the code.

package builder;

import java.awt.*;

public class SimpleRectangle {

    public SimpleRectangle(int width, int height) {
        this(0,0,width,height);
    }

    public SimpleRectangle(int x, int y, int width, int height ) {
        this(0,0,width,height,1);
    }

    public SimpleRectangle(int x, int y, int width, int height, int borderThickness) {
        this(0,0,width,height,1, Color.RED,Color.BLUE);
    }

    public SimpleRectangle(int x, int y, int width, int height, int borderThickness, Color fillColor, Color bodyColor) {
       //do smth with all these params
    }

    public void show() {

    }

    public static void main(String[] args) {
        //usages can be scattered across the code
        final SimpleRectangle simpleRectangle = new SimpleRectangle(1, 1, 10, 10, 2, Color.RED, Color.BLACK);
        simpleRectangle.show();


        final SimpleRectangle simpleRectangle1 = new SimpleRectangle(1, 1, 10, 10, 2);
        simpleRectangle1.show();


        final SimpleRectangle simpleRectangle2 = new SimpleRectangle(1, 1, 10, 10);
        simpleRectangle2.show();


        final SimpleRectangle simpleRectangle3 = new SimpleRectangle(1, 1);
        simpleRectangle3.show();


    }
}

Now, let's replace the usages of all these constructors with a single builder. To do so, we'll invoke the Replace Constructor With Builder refactoring (see Replace Constructor with Builder dialog):

File:invoke_builder.png

Let's create a new builder class with the name SimpleRectangleBuilder, located in the same package. Note that the fields are initialized with the values already used in the chained constructors.

File:builder_dialog.png

As a results, all usages of the constructors are replaced with the usages of a single builder class:

 public static void main(String[] args) {

        final SimpleRectangle simpleRectangle = new SimpleRectangleBuilder().setX(1).setY(1).setWidth(10).setHeight(10).setBorderThickness(2).setFillColor(Color.RED).setBodyColor(Color.BLACK).createSimpleRectangle();
        simpleRectangle.show();


        final SimpleRectangle simpleRectangle1 = new SimpleRectangleBuilder().setX(1).setY(1).setWidth(10).setHeight(10).setBorderThickness(2).createSimpleRectangle();
        simpleRectangle1.show();


        final SimpleRectangle simpleRectangle2 = new SimpleRectangleBuilder().setX(1).setY(1).setWidth(10).setHeight(10).createSimpleRectangle();
        simpleRectangle2.show();


        final SimpleRectangle simpleRectangle3 = new SimpleRectangleBuilder().setWidth(1).setHeight(1).createSimpleRectangle();
        simpleRectangle3.show();


    }

The builder class SimpleRectangleBuilder is created in the specified package:

package builder;

import java.awt.*;

public class SimpleRectangleBuilder {
    private int width;
    private int height;
    private int x = 0;
    private int y = 0;
    private int borderThickness = 1;
    private Color fillColor = Color.RED;
    private Color bodyColor = Color.BLUE;

    public SimpleRectangleBuilder setWidth(int width) {
        this.width = width;
        return this;
    }

    public SimpleRectangleBuilder setHeight(int height) {
        this.height = height;
        return this;
    }

    public SimpleRectangleBuilder setX(int x) {
        this.x = x;
        return this;
    }

    public SimpleRectangleBuilder setY(int y) {
        this.y = y;
        return this;
    }

    public SimpleRectangleBuilder setBorderThickness(int borderThickness) {
        this.borderThickness = borderThickness;
        return this;
    }

    public SimpleRectangleBuilder setFillColor(Color fillColor) {
        this.fillColor = fillColor;
        return this;
    }

    public SimpleRectangleBuilder setBodyColor(Color bodyColor) {
        this.bodyColor = bodyColor;
        return this;
    }

    public SimpleRectangle createSimpleRectangle() {
        return new SimpleRectangle(x, y, width, height, borderThickness, fillColor, bodyColor);
    }
}

Now you can remove the constructors from your source code, leaving the only one with the longest parameters list. You will never use it again! All usages are replaced with the references to a single builder:

package builder;

import java.awt.*;

public class SimpleRectangle {

    public SimpleRectangle(int x, int y, int width, int height, int borderThickness, Color fillColor, Color bodyColor) {
        // provide some meaningful code
    }

    public void show() {

    }

    public static void main(String[] args) {
        //usages can be scattered across the code
        final SimpleRectangle simpleRectangle = new SimpleRectangleBuilder().setX(1).setY(1).setWidth(10).setHeight(10).setBorderThickness(2).setFillColor(Color.RED).setBodyColor(Color.BLACK).createSimpleRectangle();
        simpleRectangle.show();


        final SimpleRectangle simpleRectangle1 = new SimpleRectangleBuilder().setX(1).setY(1).setWidth(10).setHeight(10).setBorderThickness(2).createSimpleRectangle();
        simpleRectangle1.show();


        final SimpleRectangle simpleRectangle2 = new SimpleRectangleBuilder().setX(1).setY(1).setWidth(10).setHeight(10).createSimpleRectangle();
        simpleRectangle2.show();


        final SimpleRectangle simpleRectangle3 = new SimpleRectangleBuilder().setWidth(1).setHeight(1).createSimpleRectangle();
        simpleRectangle3.show();


    }
}

You can make the resulting code even more concise, if you select the check boxes Optional Setters in the Replace Constructor With Builder dialog box.

Personal tools