Sure Reinier, copy it to where ever you want. It's in the Public Domain from now. Mentioning the source is nice though. :)
It was a year ago that I wrote that code for a mail conversation with Josh Bloch. I haven't thought about it until another thread brought up the builder pattern. Your points are valid, there's more to do. But we would need an IDE plugin for it and I don't have the time to write one. But maybe someone else do? That was my thought at least. Cheers, Mikael On Nov 21, 5:36 pm, Reinier Zwitserloot <[email protected]> wrote: > 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=.
