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=.
