The logic to support all of the non-specific builder magic will go into UberBuilder. GUIBuilder will be an instance if UberBuilder with specific factories pre-loaded into the cache.
The only constructor will be
This is driven by the use case. Each uberInit method will exploit the dynamic dispatch mechanism of Groovy to match to the proper uberInit method.
Consider the following calls
All three of these would create an UberBuilder with ant, swing, and dom factories pre-loaded. Other factories may be addable if the child instance exposes the factory registration methods publicly. (some UberBuilders may not want to).
First, there will be an internal registry mapping, mapping some object (usually strings) to the relevant registrations for the UberBuilder. Hence the fallback case:
We basically try to init again if we don't get a match, except we look at the internal registry cache to 'de-reference' the symbol. Usually a String, but there may be instances where we may want to intercept a class. (should we move the dereferencing to the constructor?)
This is always a de-reference. We may not even need an uberInit method, except for clarity.
If the class is assignable to FactoryBuilderSupport, we attempt to no-args construct it. If we are successful we feed it to uberInit(FactoryBuilderSupport), if not we feed it to uberInit(Object) before failing.
There are two approaches we can use here, not sure which is best.
Maps will be handled based on the type of the value argument. We may even want to allow 'unwrapped' calls via type tricks, ie
The key will be registered as a node name and the factory will be the value
The key will be a prefix to each of the nodes and it will be otherwise treated as a call with just the FactoryBuilderSupport.