A story about making a Builder that inherits the Builder

Introduction

It's natural if you think calmly, but I thought about it for a moment, so as a memo ...

Make a builder

I'll omit the Getter / Setter, but there is a Square class that has vertical and horizontal lengths in the fields.

Square.java


public class Square {
  private int width;
  private int height;
}

If you make it possible to set the value using Builder and create a class that returns the area at the end, it will be as follows.

SquareBuilder.java


public class SquareBuilder {

  public static class Builder {

    Square square = new Square();

    public Builder() {}

    public Builder width(int width) {
      square.setWidth(width);
      return this;
    }

    public Builder height(int height) {
      square.setHeight(height);
      return this;
    }

    public int build() {
      return square.getWidth() * square.getHeight();
    }
  }
}

Then, you can find the area like this

Main.java


public class Main {
  public static void main(String[] args) {
    SquareBuilder.Builder squareBuilder = new SquareBuilder.Builder();
    System.out.println("Area is:" + squareBuilder.width(5).height(10).build());
  }
}

There is no particular problem so far. : slight_smile:

Create a Builder that inherits the Builder

Next, create a Cube class that inherits from Square. (Omit Getter / Setter.)

Cube.java


public class Cube extends Square {
  private int depth;
}

Aside from whether the height was depth ...: kissing: It also inherits Builder

CubeBuilder.java


public class CubeBuilder extends SquareBuilder {

  public static class Builder extends SquareBuilder.Builder {

    private Cube cube = new Cube();

    public Builder() {}

    public Builder depth(int depth) {
      cube.setDepth(depth);
      return this;
    }

    @Override
    public int build() {
      return super.build() * cube.getDepth();
    }
  }
}

Then, you can find the volume like this.

Main.java


public class Main {
  public static void main(String[] args) {
    CubeBuilder.Builder cubeBuilder = new CubeBuilder.Builder();
    System.out.println("Volume is:" + cubeBuilder.depth(2).width(5).height(10).build());
  }
}

This code goes through compilation and requires volume, but it's actually a problem. You have to call depth () first to find the volume. : worried:

The reason is that the return values of width () and height () are of type SquareBuilder.Builder, so you can't calldepth (), which is defined only in CubeBuilder.Builder. ..

We will use Generics here.

Reference: Subclassing a Java Builder class

SquareBuilder.java


public class SquareBuilder {

  public static class Builder<T extends Builder<T>> {

    Square square = new Square();

    public Builder() {}

    public T width(int width) {
      square.setWidth(width);
      return (T) this;
    }

    public T height(int height) {
      square.setHeight(height);
      return (T) this;
    }

    public int build() {
      return square.getWidth() * square.getHeight();
    }
  }
}

CubeBuilder.java


public class CubeBuilder extends SquareBuilder {

  public static class Builder extends SquareBuilder.Builder<Builder> {

    private Cube cube = new Cube();

    public Builder() {}

    public Builder depth(int depth) {
      cube.setDepth(depth);
      return this;
    }

    @Override
    public int build() {
      return super.build() * cube.getDepth();
    }
  }
}

As a result, the return type of width () and height () will be a class that inherits SquareBuilder.Builder instead of SquareBuilder.Builder, so you need to calldepth ()first. lose.

Main.java


public class Main {
  public static void main(String[] args) {
    SquareBuilder.Builder squareBuilder = new SquareBuilder.Builder();
    System.out.println("Area is:" + squareBuilder.width(5).height(10).build());

    CubeBuilder.Builder cubeBuilder = new CubeBuilder.Builder();
    System.out.println("Volume is:" + cubeBuilder.width(5).height(10).depth(2).build());
  }
}

However, I feel a little uncomfortable because there is a Warning. : mask:

Background of posting

It's a program that puts values in POJOs with a lot of fields and outputs them in JSON format, so it became troublesome to put values in Setter one by one, and I was addicted to using Builder.

bonus

In this example, the area cannot be calculated, but Warning can be eliminated by making SquareBuilder an abstract class.

SquareBuilder.java


public class SquareBuilder {

  public abstract static class Builder<T extends Builder<T>> {

    Square square = new Square();

    public Builder() {}

    public abstract T getThis();

    public T width(int width) {
      square.setWidth(width);
      return getThis();
    }

    public T height(int height) {
      square.setHeight(height);
      return getThis();
    }

    public int build() {
      return square.getWidth() * square.getHeight();
    }
  }
}

CubeBuilder.java


public class CubeBuilder extends SquareBuilder {

  public static class Builder extends SquareBuilder.Builder<Builder> {

    private Cube cube = new Cube();

    public Builder() {}

    @Override
    public Builder getThis() {
      return this;
    }

    public Builder depth(int depth) {
      cube.setDepth(depth);
      return this;
    }

    @Override
    public int build() {
      return super.build() * cube.getDepth();
    }
  }
}

Recommended Posts

A story about making a Builder that inherits the Builder
A story about making a calculator to calculate the shell mound rate
A story about the JDK in the Java 11 era
A story about introducing Evolutions into the Play Framework
A story about making catkin_make of rosjava compatible offline
A story about making Spring + Hibernate + MySQL apps replication compatible
A murmur about the utility class
A story about hitting the League Of Legends API with JAVA
A story that struggled with the introduction of Web Apple Pay
The story that Tomcat suffered from a timeout error in Eclipse
The story of making a communication type Othello game using Scala.
A story that confirmed the profile of Yasuko Sawaguchi 36 years ago
The story of making it possible to build a project that was built by Maven with Ant
The story of making a game launcher with automatic loading function [Java]
A story about creating a service that tells a story of a portfolio by developing alone
A story about a Spring Boot project written in Java that supports Kotlin
How to operate IGV using socket communication, and the story of making a Ruby Gem using that method
A story that was embarrassing to give anison file to the production environment
[Java] Implement a function that uses a class implemented in the Builder pattern
A story about sending a pull request to MinGW to update the libgr version
A story about an arithmetic overflow that you shouldn't encounter in Ruby
The story of making an Android application that can adjust the sampling frequency of the accelerometer
A story about a super beginner participating in the AtCoder contest for the first time (AtCoder Beginner Contest 140)
A story about creating a library that operates next-generation sequencer data with Ruby ruby-htslib
A shell script that builds the OpenJDK11 source
A story about Java 11 support for Web services
A story that separates business logic and model
A story that took time to establish a connection
The story of making the existing Dockerfile GPU compatible
A story about a very useful Ruby Struct class
A story about Apache Wicket and atomic design
How to create a class that inherits class information
The story that link_to is deep (cause unknown)
A story about trying to operate JAVA File
A description that only the poster can access
About the daylight saving time that really happened
A note about the Rails and Vue process
A story about a new engineer reading a passion programmer
A story that failed using "bundle exec rubocop -a"
A story about creating a service that proposes improvements to a website using a machine learning API
About the method
About the package
A story about taking an HTTP trace using Charles to find out what requests the Java library is making to Slack
[PHP] A story about outputting PDF with TCPDF + FPDI
A small story that is sometimes useful in Maven
A story about trying to get along with Mockito
A story about trying hard to decompile JAR files
A story about reducing memory consumption to 1/100 with find_in_batches
Builder pattern that forces a set of required properties
About the matter that hidden_field can be used insanely
A command that definitely cleans the local docker environment
A story about developing ROS called rosjava with java
About a double loop that puts a For statement inside a For statement
I learned about the existence of a gemspec file
A story about starting a Java-related book club for newcomers
The story of making Dr. Oakid using LINE BOT
The story of making dto, dao-like with java, sqlite
The story that the forced update could not be implemented
The story that .java is also built in Unity 2018
A story that deepened the understanding of devise's methods user_signed_in? And current_user through error resolution
A memo of the program that allows you to realize that the probability of dice rolling is about 1/6