Edit: I'd like to point out that this question describes a theoretical problem, and I am aware that I can use constructor arguments for mandatory parameters, or throw a runtime exception if the API is used incorrectly. However, I am looking for a solution that does not require constructor arguments or runtime checking.Imagine you have a Car interface like this:public interface Car {    public Engine getEngine(); // required    public Transmission getTransmission(); // required    public Stereo getStereo(); // optional}As the comments would suggest, a Car must have an Engine and Transmission but a Stereo is optional. That means a Builder that can build() a Car instance should only ever have a build() method if an Engine and Transmission have both already been given to the builder instance. That way the type checker will refuse to compile any code that attempts to create a Car instance without an Engine or Transmission.This calls for a Step Builder. Typically you'd implement something like this:public interface Car {    public Engine getEngine(); // required    public Transmission getTransmission(); // required    public Stereo getStereo(); // optional    public class Builder {        public BuilderWithEngine engine(Engine engine) {            return new BuilderWithEngine(engine);        }    }    public class BuilderWithEngine {        private Engine engine;        private BuilderWithEngine(Engine engine) {            this.engine = engine;        }        public BuilderWithEngine engine(Engine engine) {            this.engine = engine;            return this;        }        public CompleteBuilder transmission(Transmission transmission) {            return new CompleteBuilder(engine, transmission);        }    }    public class CompleteBuilder {        private Engine engine;        private Transmission transmission;        private Stereo stereo = null;        private CompleteBuilder(Engine engine, Transmission transmission) {            this.engine = engine;            this.transmission = transmission;        }        public CompleteBuilder engine(Engine engine) {            this.engine = engine;            return this;        }        public CompleteBuilder transmission(Transmission transmission) {            this.transmission = transmission;            return this;        }        public CompleteBuilder stereo(Stereo stereo) {            this.stereo = stereo;            return this;        }        public Car build() {            return new Car() {                @Override                public Engine getEngine() {                    return engine;                }                @Override                public Transmission getTransmission() {                    return transmission;                }                @Override                public Stereo getStereo() {                    return stereo;                }            };        }    }}There's a chain of different builder classes (Builder, BuilderWithEngine, CompleteBuilder), that add one required setter method after another, with the last class containing all optional setter methods as well.This means that users of this step builder are confined to the order in which the author made mandatory setters available. Here is an example of possible uses (note that they are all strictly ordered: engine(e) first, followed by transmission(t), and finally the optional stereo(s)).new Builder().engine(e).transmission(t).build();new Builder().engine(e).transmission(t).stereo(s).build();new Builder().engine(e).engine(e).transmission(t).stereo(s).build();new Builder().engine(e).transmission(t).engine(e).stereo(s).build();new Builder().engine(e).transmission(t).stereo(s).engine(e).build();new Builder().engine(e).transmission(t).transmission(t).stereo(s).build();new Builder().engine(e).transmission(t).stereo(s).transmission(t).build();new Builder().engine(e).transmission(t).stereo(s).stereo(s).build();However, there are plenty of scenarios in which this is not ideal for the builder's user, especially if the builder has not just setters, but also adders, or if the user cannot control the order in which certain properties for the builder will become available.The only solution I could think of for that is very convoluted: For every combination of mandatory properties having been set or having not yet been set, I created a dedicated builder class that knows which potential other mandatory setters need to be called before arriving at a state where the build() method should available, and each one of those setters returns a more complete type of builder which is one step closer to containing a build() method.I added the code below, but you might say that I'm using the type system to create a FSM that lets you create a Builder, which can be turned into either a BuilderWithEngine or BuilderWithTransmission, which both can then be turned into a CompleteBuilder, which implements the build() method. Optional setters can be invoked on any of these builder instances.public interface Car {    public Engine getEngine(); // required    public Transmission getTransmission(); // required    public Stereo getStereo(); // optional    public class Builder extends OptionalBuilder {        public BuilderWithEngine engine(Engine engine) {            return new BuilderWithEngine(engine, stereo);        }        public BuilderWithTransmission transmission(Transmission transmission) {            return new BuilderWithTransmission(transmission, stereo);        }        @Override        public Builder stereo(Stereo stereo) {            super.stereo(stereo);            return this;        }    }    public class OptionalBuilder {        protected Stereo stereo = null;        private OptionalBuilder() {}        public OptionalBuilder stereo(Stereo stereo) {            this.stereo = stereo;            return this;        }    }    public class BuilderWithEngine extends OptionalBuilder {        private Engine engine;        private BuilderWithEngine(Engine engine, Stereo stereo) {            this.engine = engine;            this.stereo = stereo;        }        public CompleteBuilder transmission(Transmission transmission) {            return new CompleteBuilder(engine, transmission, stereo);        }        public BuilderWithEngine engine(Engine engine) {            this.engine = engine;            return this;        }        @Override        public BuilderWithEngine stereo(Stereo stereo) {            super.stereo(stereo);            return this;        }    }    public class BuilderWithTransmission extends OptionalBuilder {        private Transmission transmission;        private BuilderWithTransmission(Transmission transmission, Stereo stereo) {            this.transmission = transmission;            this.stereo = stereo;        }        public CompleteBuilder engine(Engine engine) {            return new CompleteBuilder(engine, transmission, stereo);        }        public BuilderWithTransmission transmission(Transmission transmission) {            this.transmission = transmission;            return this;        }        @Override        public BuilderWithTransmission stereo(Stereo stereo) {            super.stereo(stereo);            return this;        }    }    public class CompleteBuilder extends OptionalBuilder {        private Engine engine;        private Transmission transmission;        private CompleteBuilder(Engine engine, Transmission transmission, Stereo stereo) {            this.engine = engine;            this.transmission = transmission;            this.stereo = stereo;        }        public CompleteBuilder engine(Engine engine) {            this.engine = engine;            return this;        }        public CompleteBuilder transmission(Transmission transmission) {            this.transmission = transmission;            return this;        }        @Override        public CompleteBuilder stereo(Stereo stereo) {            super.stereo(stereo);            return this;        }        public Car build() {            return new Car() {                @Override                public Engine getEngine() {                    return engine;                }                @Override                public Transmission getTransmission() {                    return transmission;                }                @Override                public Stereo getStereo() {                    return stereo;                }            };        }    }}As you can tell, this doesn't scale well, as the number of different builder classes required would be O(2^n) where n is the number of mandatory setters.Hence my question: Can this be done more elegantly?(I'm looking for an answer that works with Java, although Scala would be acceptable too)
Java: How to implement a step builder for which the order of setters doesn't matter?
design patterns;builder pattern