2

First, I have to admit my problem is similar to Singleton with Arguments in Java

I read it, but the solution doesn't work for me. I know the factory pattern is the best solution to that problem.

Here is my problem. I create a "singleton" class to provide some common function, for example get a global configuration parameter. This class need a handler to access the system resources, for example read the configuration file. Cause this class just act as a lib, the handler must pass in from outside, and the Handler is a system class.

So, I write my code in this way:

public class SingletonGlobalParameters {
    private static final SingletonGlobalParameters instance = new SingletonGlobalParameters ();

    private boolean initial = false;

    private String aParameter = null;

    private SingletonGlobalParameters () { }

    public static SingletonGlobalParameters getInstance() {
            if (initial == false) {
                throw exception...
            }
            return instance;
    }

    public void init(Handler h) {
        if (initial == false) {
            Handler fileHandler = h;
            aParameter = fileHandler.read(); // something like this
            initial = true;
        }
    }

    public int getParameter() {
        return aParameter;
    }
}

I remove synchronization stuff to make question clear. This implement looks ugly, right? The class must guarantee to initialize before use.

Any good ideas? Thanks very much, this problem has troubled me for some time.


OK! I give the real world problem. This is a Android problem.

public class Configuration {
    private static final Configuration instance = new Configuration ();

    private boolean initial = false;

    private long timeStamp = -1;

    private Configuration () { }

    public static Configuration getInstance() {
            if (initial == false) {
                throw exception...
            }
            return instance;
    }

    public void load(Context context) {
        if (initial == false) {
            SharedPreferences loader = context.getSharedPreferences("Conf", Context.MODE_PRIVATE);
            timeStamp = loader.getInt("TimeStamp", 0);              
            initial = true;
        }
    }

    public int getTimeStamp() {
        return timeStamp;
    }
}

Is this make question clearer?

Community
  • 1
  • 1
Kane
  • 868
  • 1
  • 9
  • 18

2 Answers2

2

The right pattern is the one allowing you to do things you need. Do not be so dogmatic. Singleton with a parameter is widely used and acepted in android environment (parameter is usually context). But in plain java environment, dependency injection would be better as it decouples code using you singleton from the fact it is singleton, and modalities of its creation. There are a plenty of DI frameworks,like picocontainer, spring, google guice - just pick your favorite

Konstantin Pribluda
  • 12,329
  • 1
  • 30
  • 35
  • You discovered my secret. :D The handler I talked about actually is the applicationContext. – Kane Feb 02 '12 at 07:31
  • This pattern is acepted on android. Though there are DI-Frameworks like guicefor android, they are just too heavy for most apps. So we will have to stick with parametrized singleton until something trully lightweight comes. I'mmyself developer of picocontainer, and feel that it is too heavy for use on android. So I'm working on another framework: https://github.com/ko5tik/andject – Konstantin Pribluda Feb 02 '12 at 07:49
  • Thanks. Yes, DI is too heavy for my problem, I think I need redesign in a different way. – Kane Feb 02 '12 at 08:00
1

EDIT: When I wrote this answer, the question had no context - we didn't know it was an Android app. It may be that it's not a bad solution in this case; but I would at least think about other approaches. I'm leaving my answer below for the more general case.

I would attempt to move away from the singleton pattern to start with.

Why is each configuration parameter needed from many places? Could you encapsulate each aspect of configuration (possibly multiple parameters in a single aspect in some cases) and then use dependency injection (e.g. with Guice) to make those encapsulated versions available to the components that need them?

It's hard to give concrete advice when we really don't know what kind of app you're writing, but in general it's a good idea to move away from global state, and dependency injection often provides a clean way of doing this. It's not a panacea, and it could be that in some cases you can redesign in a different way, but it would be my first thought.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks, I think redesign maybe the best choice for me. – Kane Feb 02 '12 at 07:54
  • As he is on android, there is global state with application conetxt. You need this almost for anything coming from OS, and you shall be very careful in (avoiding) holding references to it - so parametrized singleton is least evil – Konstantin Pribluda Feb 02 '12 at 08:18
  • @KonstantinPribluda: Unfortunately when I answered, there was no context at all - we didn't know this was an Android application. I'll leave this answer up for the more general case... – Jon Skeet Feb 02 '12 at 08:22
  • Application context is not activity context. So I think holding Application context maybe is not so dangerous. – Kane Feb 02 '12 at 08:36