I am developing in Java now for some 27 years, the most part of it for a living. There are many clever things I’ve seen in this time written and invented by others. So, I was really surprised when I had an idea today I cannot remember I have ever seen before. I wrote a first implementation and it seems to work. And as it a quite basic structure I ask myself: Has no-one ever ever done this so far?
It’s about the following thing: A quite common pattern for builders is the DSL-like approach of step-wise subclasses. I learned this while fiddling around with JOOq and implemented it myself several times somehow like this:
class SomeBuilder { int field1; String field2; public Step2 withField1(int field1) { this.field1=field1; return new Step2(); } public class Step2 { public BuildStep withField2(String field2) { this.field2=field2; return new BuildStep(); } } public class BuildStep { public SomeThing build() { return new SomeThing(field1,field2); } } } ... SomeThing someThing=new SomeBuilder().withField1(15).withField2(''hello'').build();
This is a known pattern I like to use for more complex builders when it is important not to forget fields in the building process. Disadvantage: Lots of class instances are created during the building process. And it looks rather scattered as the business logic is hidden in all that subclasses. A „normal” builder just returns itself again and again so that nothing has to be created. And all methods are at the same level next to each other. But a „normal” builder cannot guide you through the building process – you always have access to all build methods.
Or – can it?
What if we split the API of the builder into chunks containing only some of the methods and guiding the caller through the process just as the class-based approach above. Java has a language feature for this: interfaces:
class SomeBuilder { public interface Step1 { Step2 withField1(int field1); } public interface Step2 { BuildStep withField2(String field2); } public interface BuildStep { SomeThing build(); } public static class Process implements Step1,Step2,BuildStep { int field1; String field2; public Step2 withField1(int field1) { this.field1=field1; return this; } public BuildStep withField2(String field2) { this.field2=field2; return this; } public SomeThing build() { return new SomeThing(field1,field2); } } public static Step1 create() { return new Process(); } } ... SomeThing someThing=SomeBuilder.create().withField1(15).withField2(''hello'').build();
This does exactly the same thing and allows exactly the same guidance as the class-based approach above. Ok, you have to write „SomeBuilder.create()” instead of „new SomeBuilder()”, but that’s really not a difference – and if the builder is generated by a static „SomeThing.builder()” method, there is no difference in calling at all.
This approach also seems to have the advantage that it’s really easy to model optional fields. If „field2” can be left out, it’s simple to model that: You just add another interface
public interface Step2OrBuildStep extends Step2,BuildStep {}
… and let Step1::withField1 (and Process::withField1) return this interface:
public interface Step1 { Step2OrBuildStep withField1(); } ... public Step2OrBuildStep withField1(int field1) { this.field1=field1; return this; }
The really nice thing as I see it is that building process and build semantics are totally separated from each other: The builder can be written as usual. Only the interfaces create the guidance through the methods. Yes, you have the duplication of the builder methods in the interfaces – but I don’t think this to be really bad. After all, the IDE can to most of the work („create missing methods”) if the interfaces are written first and the builder process class afterwards. And there is only one class instance generated through the building process, not a number of tiny subclasses.
Is this really a clever idea or do I oversee something?