views:

351

answers:

4

Joshua Bloch's Effective Java describes a Builder Pattern that can be used to build objects with several optionally customizable parameters. The naming convention he suggests for the Builder functions, which "simulates named optional parameters as found in Ada and Python," doesn't seem to fall in line with Java's standard naming convention. Java functions tend to rely on a having a verb to start the function and then a noun-based phrase to describe what it does. The Builder class only has the name of the variable that's to be defined by that function.

Are there any APIs within the Java standard libraries that makes use of the Builder Pattern? I want to compare the suggestions in the book to an actual implementation within the core set of Java libraries before pursuing its use.

+2  A: 

It's only defined (not implemented) in the standard library, however, the JDBC DataSource objects remind me of the builder pattern. You create a DataSource object and then you set a number of properties and then you make a connection.

Here's a code example...

DataSource ds = (DataSource)ctx.lookup("jdbc/AcmeDB");
ds.setServerName("my_database_server");
ds.setDescription("the data source for inventory and personnel");
Connection con = ds.getConnection("genius", "abracadabra");
Pace
+4  A: 

I'm not sure about within the core JDK, but good examples can be found in Guava. MapMaker is probably the best example I can think of off the top of my head. For example, from the docs:

ConcurrentMap<Key, Graph> graphs = new MapMaker()
    .concurrencyLevel(32)
    .softKeys()
    .weakValues()
    .expiration(30, TimeUnit.MINUTES)
    .makeComputingMap(
        new Function<Key, Graph>() {
          public Graph apply(Key key) {
            return createExpensiveGraph(key);
          }
        });

Yes, this sort of thing can go against the grain of "standard" Java naming, but it can also be very readable.

For situations where you're not returning "this" but a new object (typically with immutable types) I like a "with" prefix - Joda Time uses that pattern extensively. That's not the builder pattern, but an alternative and related construction form.

Jon Skeet
+2  A: 

One example within the JDK (6.0 and above) is GroupLayout.

An example of using GroupLayout is:

    layout.setHorizontalGroup(layout.createSequentialGroup()
        .addComponent(label)
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addComponent(textField)
            .addGroup(layout.createSequentialGroup()
              .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                  .addComponent(caseCheckBox)
                  .addComponent(wholeCheckBox))
              .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                  .addComponent(wrapCheckBox)
                  .addComponent(backCheckBox))))
     .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
    );

Although GroupLayout is intended for GUI builders, it can be written by hand, and it is quite fluent, once you're used to it.

Grundlefleck
The more I think about this, the less I'm convinced that it is a Builder pattern. The prefix "add" implies that multiple instances of the same parameter can be defined, where the builder is just defining the preset instances that will be available.
Fostah
I don't think, that a builder should be restricted to just configuring a single instance. This example really shows the benefits of a builder pattern where a complex structure of instances is constructed in a fluent form.
Ralf Edmund
+1  A: 

ProcessBuilder is very much an instance of the builder pattern, but not quite using the java naming conventions.

 ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
 Map env = pb.environment();
 env.put("VAR1", "myValue");
 env.remove("OTHERVAR");
 env.put("VAR2", env.get("VAR1") + "suffix");
 pb.directory(new File("myDir"));
 Process p = pb.start();

In the SQL package, PreparedStatement could be considered an instance of the builder pattern:

 PreparedStatement stmt = conn.prepareStatement(getSql());
 stmt.setString(1, ...);
 stmt.setString(2, ...);
 ResultSet rs = stmt.executeQuery();
 ...
 stmt.setString(2, ...);
 rs = stmt.executeQuery();
 ...
Sarah Happy
It isn't a fullworthy builder pattern if you can't chain methods.
BalusC