Looks interesting. Some comments:

1. Wouldn't it be technically nicer to let the builder contain the
code mapping builder properties onto the constructor? So, have a
constructor listing all the fields (optional and required), which just
assigns them to the (probably final) fields. I guess this is code
duplication, but clearly you need either an IDE plugin, a command line
tool, or something like Project Lombok to actually write all this code
for you; it's ludicrous to do it by hand. Thus, verbosity is
irrelevant.

2. One of the advantages of a builder is that you can use them as a
StringBuilder-esque device; something to pass around between different
methods if a batch of them are each responsible for only building a
part of the whole NutritionFacts object. However, by forcing the
ordering, you sort of ruin the ability to do this at least for the
required parameters. A fix that works as well with the type system as
this concept of yours seems impossible without at least something like
Michael Ernst's Checking Framework (and a custom plugin for it), but
you can alleviate the problem by including setters for the required
fields in the final builder returned. That way, the method that starts
the build process is forced to pick defaults, but later methods can
override them.


This seems like an excellent idea for a lombok plugin. May I copy your
post to the lombok newsgroup?


On Nov 21, 4:24 pm, mikaelgrev <[email protected]> wrote:
> Builder patterns are cool. When I saw Joshua Bloch's in Effective Java
> 2 I just couldn't help wanting slightly more. So I created another one
> that is simpler and more secure to use. It is slightly more complex to
> write though.
>
> The Effective Java builder pattern:
>
> NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories
> (100).sodium(35).carbohydrate(27).build();
>
> The problem is that the required fields are not documented in that
> code.
> Also, the "new ButritionFacts.Builder" notion will make a lot of Java
> developers trip.
>
> Instead, how about:
>
> NutritionFacts cocaCola = NutritionFacts.servingSize(240).servings
> (8).calories(100).sodium(35).carbohydrate(27).build();
>
> What is good about it is that it is extremely easy to read. It scales
> with both the numbers of required fields AND optional fields. And it
> is completely type safe.
> And, you can absolutely never go wrong. In every stage of the required
> args there is only one valid method to call. It works very well with
> code completion...
>
> The only downside is that the implementation is slightly more complex
> for the required parameters.
>
> If the notion doesn't look enough like a creation of an object a
> simple variation with all the benefits can look like:
>
> NutritionFacts cocaCola = new NutritionFacts.Builder().servingSize
> (240).servings(8).calories(100).sodium(35).carbohydrate(27).build();
>
> The best would be if an IDE plugin could spit out the code
> automatically after a "Build Builder class..." command.
>
> Hope someone finds this useful.
>
> Cheers,
> Mikael Grev
>
> public final class NutritionFacts
> {
>     // Required
>     private final int servingSize, servings;
>
>     // Optional
>     private final int calories, fat, sodium, carbohydrate;
>
>     private NutritionFacts(Builder builder)
>     {
>         servingSize   = builder.servingSize;
>         servings      = builder.servings;
>         calories      = builder.calories;
>         fat           = builder.fat;
>         sodium        = builder.sodium;
>         carbohydrate  = builder.carbohydrate;
>     }
>
>     public static ServingsArg servingSize(int servingSize)
>     {
>         return new ServingsArg(servingSize);
>     }
>
>     public final static class ServingsArg
>     {
>         private final int servingSize;
>
>         private ServingsArg(int servingSize)
>         {
>             this.servingSize = servingSize;
>         }
>
>         public Builder servings(int servings)
>         {
>             return new Builder(servingSize, servings);
>         }
>     }
>
>     public final static class Builder
>     {
>         // Required
>         private final int servingSize;
>         private final int servings;
>
>         // Optional
>         private int calories = 0;
>         private int fat = 0;
>         private int sodium = 0;
>         private int carbohydrate = 0;
>
>         private Builder(int servingSize, int servings)
>         {
>             this.servingSize = servingSize;
>             this.servings    = servings;
>         }
>
>         public NutritionFacts build()
>         {
>             return new NutritionFacts(this);
>         }
>
>         public Builder calories(int i)
>             {this.calories = i; return this; }
>         public Builder fat(int i)
>             {this.fat = i; return this; }
>         public Builder sodium(int i)
>             {this.sodium = i; return this; }
>         public Builder carbohydrate(int i)
>             {this.carbohydrate = i; return this; }
>    }
>
>
>
> }

--

You received this message because you are subscribed to the Google Groups "The 
Java Posse" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/javaposse?hl=.


Reply via email to