How to create builder chain

I would like to create builder chain where I can provide different sets of methods based on the value of i. If I can use these intermediate builder classes then I can limit the available methods at compile-time rather than relying on runtime checks. (The intermediate builder classes aren't intended to be exposed to the end user, they're just there to provide different sets of methods after calling set().)

public class SomeClass {
    public static class SomeClassBuilder {
        public <What should I return ?> set(int i) {
            switch (i) {
               case 1:
                   return new Case1Builder();
                   break;
               case 2:
               case 3:
                   return new Case2And3Builder();
                   break;
               case 4:
                   return new Case4Builder();
                   break;
               default:
                   return this;
            }
        }

        public SomeClass.SomeClassBuilder build() {
        }
    }

    public static final class Case1Builder() {
        public SomeClass.Case1Builder set1() {
        }
    }

    public static final class Case2And3Builder() {
        public SomeClass.Case1Builder set2And3() {
        }
    }

    public static final class Case4Builder() {
        public SomeClass.Case1Builder set4() {
        }
    }
}

And then from my driver class, I could do below:

final SomeClass someClass = new SomeClass.SomeClassBuilder(1).set1().build();
final SomeClass someClass = new SomeClass.SomeClassBuilder(2).set2And3().build();

Is it possible? Maybe using generics?

728x90

2 Answers How to create builder chain

It's not possible. You can return one of several types, but since return types are compile-time you have to declare a supertype of those types. That would be Object, here. Obviously, returning Object isn't useful.

You can't return one of three types and expect the compiler to be able to provide access to different methods based on which of the three is returned. The actual returned type is a runtime artifact, while the list of methods you can call is a compile-time decision.

If you want to do it you'll need multiple set methods.

public Case1Builder set1();
public Case2And3Builder set2Or3();
public Case4Builder set4();
public GenericCaseBuilder setOther();

6 days ago

To do things the way you're trying to accomplish them, you'd want to do something like this:

public class SomeClass {
    public static class SomeClassBuilder implements CaseBuilder {
        public CaseBuilder set(int i) {
            switch (i) {
               case 1:
                   return new Case1Builder();
                   break;
               case 2:
               case 3:
                   return new Case2And3Builder();
                   break;
               case 4:
                   return new Case4Builder();
                   break;
               default:
                   return this;
            }
        }

        @Override
        public SomeClass build() {...}
    }

    public static final class Case1Builder() implements CaseBuilder {
        @Override
        public SomeClass build() {...}
    }

    public static final class Case2And3Builder implements CaseBuilder {
        @Override
        public SomeClass build() {...}
    }

    public static final class Case4Builder implements CaseBuilder {
        @Override
        public SomeClass build() {...}
    }


   public interface CaseBuilder {
      public SomeClass build();
   }
}

However, this is a lot more complicated than it needs to be, and isn't really a Builder pattern. I think what you're looking for is actually a Factory pattern, or possibly a FactoryFactory.

6 days ago