The trick here is Data Types. This is something that Java is very strict about, which makes this so much easier. What you need to do, is have a small class that only your primary can create an instance from. The easiest way is to place this as a sub-class to the primary class. This small class will be used to parse along as an argument to a static method in each "extender" class, who’s job is to return an instance of themselves. Meanwhile we will keep each "extender" constructor private, so that no other can access it. And we will make each class final, so that they cannot be extended in order to bypass this protection.
This is our primary class:
public final class MyPrimary { public MyExtender extender(String param) { MyTransport transport = new MyTransport(); transport.arguments = new Object[] { (Object) param }; return (MyExtender) MyExtender.getInstance( transport ).instance; } public final static interface MyDataType {} public final static class MyTransport { private MyTransport() {} Object[] arguments; MyDataType instance; } }
This is one of our extenders:
public final class MyExtender implements MyDataType { public static MyTransport getInstance(MyTransport transport) { transport.instance = (MyDataType) new MyExtender( (String) transport.arguments[0] ); return transport; } private MyExtender(String param) { ... } }
In order to get an instance from MyExtender, you will need to parse through it's getInstance method. However, this method requires a MyTransport argument, which only the primary class can create. From the getInstance method, it will attach an instance of itself and then return the MyTransport object to the primary class. And by implementing MyDataType, you can use the same MyTransport class for any extender classes as they will all be able to be casted to the same data type.
That is all that there is to it. And like mentioned above, this can be used in any OOP language. In some however, you will need some manual checking of data types. PHP for an example does not really care about data types, so you will need to do a manual instanceOf check in the extender getInstance methods to make sure that the argument really is a MyTransport object. But that is not all that difficult to implement.