mercredi 6 janvier 2016

How to implement a configurable singleton?

This question is related to Android but can also be asked in other situations. I need to create a library where singletons are exposed; or I want to ensure only one instance of my classes exists and can be grabbed anywhere in the code without passing references.

But thoses singletons needs some parameters. For instance in Android, a Context object is often needed. I must also precise that since I provide a library, I want things to be easy for the user and I do not have control of the Application class in Android (this class can sometimes be used to manage object instances for a whole app).

One known solution is to do the following:

static MySingleton sInstance;
MySingleton.getInstance(Context c) {
    if (sInstance == null) {
        sInstance = new MySingleton(c.getApplicationContext());
    }
    return sInstance;
}

But it is strange since the parameter of getInstance is actually only used at the first creation of the singleton.

I could provide a setter to the singleton and asks the developer to correctly set the needed parameters, but some strange situations could arise:

// Good usage
MySingleton.getInstance().setContext(context);
MySingleton.getInstance().doSomethingThatRequiresContext(); // OK

// Bad usage
MySingleton.getInstance().doSomethingThatRequiresContext(); // Error!
MySingleton.getInstance().setContext(context);

I could check at the start of each method if the singleton is correctly configured and launch some exceptions in case of a bad state, but the API is less straightforward to use:

MySingleton.getInstance().setContext(context);

try {
    MySingleton.getInstance().doSomethingThatRequiresContext();
}
catch(BadSingletonConfiguration e) { }

Even if I use runtime exceptions, it would be dangerous to use.

Unless I kindly ask the user to manually create the instance and to ensure himself only one instance will exist, I do not see a good solution.

Would you have some better ideas?

Aucun commentaire:

Enregistrer un commentaire