Pages

Friday, August 23, 2013

Controlled Environment

You are building a library of some sort, and you want to have a primary class with additional "extender" classes which all should be accessed through your primary one. Why? Don't know, hopefully you do since your the one making it. However, what is to stop anyone from accessing your "extender" classes directly? You could add your "extender" classes as sub-classes to the primary and make your constructors private or protected. But if your planing on expanding this library a great deal, you will end up with a pretty large file at the end. And splitting your "extender" classes into single files with private and protected constructors will just ensure that not even your primary class will be able to create instances of them. So what's left? I know that some languages actually has a feature which allows you to lock a class and define whom has access to create an instance. I have not worked with Java for long, so I don't know whether or not this feature exists in Java. But there are other ways of doing this, which will actually work in other OOP capable languages as well.

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.

No comments:

Post a Comment