Running on Java 24-ea+28-3562 (Preview)
Home of The JavaSpecialists' Newsletter

253Builder Pattern GoF vs Effective Java

Author: Dr. Heinz M. KabutzDate: 2018-02-26Java Version: 1.1Category: Tips and Tricks
 

Abstract: What is the best-case computational time complexity for finding a method inside a class via reflection? In this newsletter we do not answer that question. Instead, we look at the GoF Builder and wonder whether anyone has ever used it in Java.

 

Welcome to the 253rd edition of The Java(tm) Specialists' Newsletter. Someone called me "Uncle Heinz" in our Slack channels the other day. There can be only one "Uncle" in our industry - The One And Only Uncle Bob :-) In Greece we use the affectionate "Barbar Heinz". But that sounds too close to "Barbarian Heinz". Well, I am German, and you know what the Greeks think of the Teutons, so perhaps that is fitting? Google Translate converts barbar to barbecue. Now that's not a bad one: "Barbecue Heinz". But let's keep it at "Heinz" - that's a strange enough name already :-)

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Builder Pattern GoF vs Effective Java

At school, we learn how to write new Java classes. What our professors don't tell us, is that we seldom get a chance to invent new code in the real world. Most of our time is spent fiddling with existing classes. Either we fix bugs left behind by our predecessors or hack in new features. If we do get the chance to write new code, we rely on frameworks to get the job done quicker.

This is why we need to grasp design patterns. How can we process annotations without first understanding Visitor? Patterns extend our vocabulary and thus speed up communication within our team. Instead of jotting down six classes on a napkin, we incant "Decorator" and our audience knows what we mean. This saves time and avoids misunderstandings.

When the design patterns revolution hit in the mid 90s, they said we couldn't learn them in a course. They told us: Only way to grok this stuff is through a study group. We tried that. It was a fun, but rather inefficient, way to spend our lunch breaks. We could not scale beyond a gaggle of super dedicated geeks. Why spend our lunch break thinking, when we could sit in the sunshine enjoying a latte? So I ignored the naysayers and wrote the first "Java Design Patterns Course" back in 2001. It educated quicker than our study group. Hundreds of Java programmers learned advanced object orientation. They became more efficient programmers and better communicators.

The first four editions of my patterns training did not contain the Builder Pattern. My include-filter was have I ever used this pattern in real code? I hadn't. I scoured the JDK and came up empty. Surprised? Before you send me an angry email, pointing with indignation at the Java 8 Calendar.Builder, read on.

Builder vs Builder

GoF Builder is simply a strategy for creating things. The intent of the Calendar.Builder is different. It hails from Effective Java [ISBN 0134685997] and addresses the telescoping constructors problem. As you know, Java has neither default nor named parameters. Thus when Socket has two optional parameters, we will need 4 constructors:

Socket()
Socket(String host)
Socket(int port)
Socket(String host, int port)

Add one parameter boolean ssl and we now need 8 constructors:

Socket()
Socket(String host)
Socket(int port)
Socket(String host, int port)
Socket(boolean ssl)
Socket(String host, boolean ssl)
Socket(int port, boolean ssl)
Socket(String host, int port, boolean ssl)

Since Java does not have named parameters either, things get real funky when parameters are of the same type. For example, let's add int timeout. And let's try to make both port and timeout optional. This would result in ambiguous constructors:

Socket(int port)
Socket(int timeout)

The Effective Java [ISBN 0134685997] Builder idiom solves this by creating an inner static class Builder, such as:

public class Socket {
  private final int port;
  private final String host;
  private final boolean ssl;
  private final int timeout;

  private Socket(Builder builder) {
    // Better to pass Builder into constructor than individual
    // parameters - thanks Carlos Solórzano (@carlosalejand)
    this.port = builder.port;
    this.host = builder.host;
    this.ssl = builder.ssl;
    this.timeout = builder.timeout;
  }

  public static class Builder {
    private int port = 0;
    private String host = null;
    private boolean ssl = false;
    private int timeout = 0;

    public Builder port(int port) {
      this.port = port;
      return this;
    }

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

    public Builder ssl(boolean ssl) {
      this.ssl = ssl;
      return this;
    }

    public Builder timeout(int timeout) {
      this.timeout = timeout;
      return this;
    }

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

We only need one constructor in Socket and clients can create variations of Socket with the Builder:

Socket s1 = new Socket.Builder().port(8080).timeout(60).build();
Socket s2 = new Socket.Builder().ssl(true).build();

If Java had default and named parameters, we could write this as:

// in the distant future, Java might be as cool as Kotlin
public class SocketJavaX {
  private final int port;
  private final String host;
  private final boolean ssl;
  private final int timeout;

  public SocketJavaX(int port=0, String host=null,
                      boolean ssl=false, int timeout=0) {
    this.port = port;
    this.host = host;
    this.ssl = ssl;
    this.timeout = timeout;
  }
}

Our client code would also be simpler:

SocketJavaX s1 = new Socket(port=8080, timeout=60);
SocketJavaX s2 = new Socket(ssl=true);

The Effective Java [ISBN 0134685997] Builder idiom would become obsolete. The idiom is a workaround for a missing language feature, rather than an OO design pattern.

One place where I expected to perhaps see the GoF Builder was reflection. When you call Class.getMethod(), you get a defensive copy of the Method object. If you set it to be accessible, it won't affect any other instances of the same Method. This, of course, is an example of the Prototype Pattern, rather than the Builder. But when I was researching the Builder, I was hopeful that I had found the elusive yeti.

To understand how getMethod() works, I stepped through the JDK code with a debugger. And in doing so, discovered a very interesting anomaly that has been with us since Java 5. But this newsletter is already too long. I will write up the rest and send it tomorrow.

Kind regards from Crete

Heinz

P.S. Did you enjoy this writing? Have you noticed an improvement over past newsletters? If so, there is a reason. I spent the last four Thursday evenings learning how to produce punchier prose. You can too - get the course here for $87. Each lesson is gold.

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '24 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...