0

Initialize a singleton by configure file is suitable or not?

I notice that the constructor of singleton should not have any parameter, the reason is that if you need use parameters to configure your object, probably that should not be singleton. Seems this sentence very famous, but indeed there are serval cases are special:

e.g. We design a simple distributed system to deal with tons of users' query:

  • only one central server
  • n sub servers, each sub server connecting to central server
  • there is no connections between sub servers

Obviously, we may design the "central server" as singleton, the details like this:

  • enum ServerType;
  • abstract class Server;
  • class CentralServer inherit from Server;(CentralServer is singleton)
  • class SubServer inherit from Server;
  • class Query;
  • ... ... ...

But the central server need some configuration, such as:

  • serverName
  • description
  • portNum-ipAddress map
  • the list of its sub servers
  • the size of BlockingQueue
  • ... ... ...

How to initialize the central server by these properties?
My current solution:

  • using the configure file to finish this part job.
  • I define another class called Configuration.

So the current constructor of central server like this:

class CentralServer extends Server implements Runnable, ....... {
    ....
    ....
    private static CentralServer _instance;
    private CentralServer () {
        super();
        .... 
        serverName = Configuration.getCentralServerName();
        description = Configuration.getCentralServerDescription();
        Configuration.initCentralServerPortNumIpMap(portNumIpMap);
        Configuration.initCentralServerSubServersList(subServersList);
        sizeBlockingQueue = Configuration.initCentralServerBlockingQueueSize();
        ....
    }

    public CentralServer getInstance() {
        if (_instance == null) {
            _instance = new CentralServer();
        }
        return _instance;
    }
    ....
    ....
}

The Configuration class, will read and analyze configuration-file, to get out of configuration info.


My Question:
  • Initialize singleton like this suitable or not, if not, please give out more suitable approach

  • I also need configure all sub servers, so seems the Configuration class is too heavy, should I split the Big Configuration class into two sub class? class CentralConfiguration, and class SubConfiguration?

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
Zhaonan
  • 939
  • 1
  • 11
  • 20

3 Answers3

2

Unfortunately, your implementation for a Singelton is WRONG!! Simply because it is not thread safe.

public CentralServer getInstance() {
    if (_instance == null) {   // race condition possible here 
        _instance = new CentralServer();
    }
    return _instance;
}

Two threads might enter this critical section and evaluate _instance==null to true, and two different instances will be created. You can simply instantiate your instance statically.

private final static CentralServer INSTANCE = new CentralServer();

public static CentralServer getInstance() {
    return INSTANCE;
}

However, the best way to implement singeltons is to use enums

public enum CentralServer { // the best way to implement singletons, due to the author of Effective Java  
INSTANCE;

private CentralServer() {
}
}

This gives you serialisation for free. However, I dont think that you need a singelton at all, singeltons are usually Anti patterns. Check this out.

In your code, CentralServer has a high dependency on Configuration which I don't think is a good thing, you should see Configuration as a dependency

class CentralServer{
 private final Configuration serverConf;

 private CentralServer(Configuration serverConf){  // inject configuration
   this.serverConf = serverConf;
 }
 public static CentralServer createCentralServer(Configuration serverConf){ // static factory perhaps
  return new CentralServer(serverConf);
 }
}

This will give you more flexibility to change or mock configuration. I think Factory pattern would be more appropriate here.

Community
  • 1
  • 1
Sleiman Jneidi
  • 22,907
  • 14
  • 56
  • 77
1

Initialize singleton like this suitable or not, if not, please give out more suitable approach:

It is not a suitable approach, because the implementation is not threadsafe yet and it can be broken f.e. via reflection. You should consider reading Effective Java by Joshua Bloch on this topic.

Better would be to create an enum singleton, because this approach is more flexible for later changes, has threadsafe instanciating and is unbreakable.

EDIT: example .

I also need configure all sub servers, so seems the Configuration class is too heavy, should I split the Big Configuration class into two sub class? class CentralConfiguration, and class SubConfiguration?

For configuration purposes, there is usually a config.xml file or a config.properties file somewhere to read important preconfigurations. After creating an instance, you should extract the information from such a file and write out necessary changes when shutting down. But as always, many ways lead to rome.

Community
  • 1
  • 1
SME_Dev
  • 1,880
  • 13
  • 23
1

It is perfectly acceptable to make use of external resources during the initialization of your singleton. A common user of the Singleton pattern is loggers and they are almost always configured from external data files.

It does make initialization more complicated but it is not impossible to make a fully tread-safe singleton that accesses external resources such as configuration files. They can even make use of other singletons such as connection pools if their configuration requires database access.

The other answers to this question correctly deal with the actual problems with your singleton initialization.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213