简体   繁体   中英

Generating singletons

This might sound like a weird idea and I haven't thought it through properly yet.

Say you have an application that ends up requiring a certain number of singletons to do some I/O for example. You could write one singleton and basically reproduce the code as many times as needed.

However, as programmers we're supposed to come up with inventive solutions that avoid redundancy or repetition of any kind. What would be a solution to make multiple somethings that could each act as a singleton.

PS: This is for a project where a framework such as Spring can't be used.

You could introduce an abstraction like this:

public abstract class Singleton<T> {
  private T object;

  public synchronized T get() {
    if (object == null) {
      object = create();
    }
    return object;
  }

  protected abstract T create();
}

Then for each singleton, you just need to write this:

public final Singleton<Database> database = new Singleton<Database>() {
  @Override
  protected Database create() {
    // connect to the database, return the Database instance
  }
};

public final Singleton<LogCluster> logs = new Singleton<LogCluster>() {
  ...

Then you can use the singletons by writing database.get() . If the singleton hasn't been created, it is created and initialized.

The reason people probably don't do this, and prefer to just repeatedly write something like this:

private Database database;

public synchronized Database getDatabase() {
  if (database == null) {
    // connect to the database, assign the database field
  }
  return database;
}

private LogCluster logs;

public synchronized LogCluster getLogs() {
  ...

Is because in the end it is only one more line of code for each singleton, and the chance of getting the initialize-singleton pattern wrong is pretty low.

However, as programmers we're supposed to come up with inventive solutions that avoid redundancy or repetition of any kind.

That is not correct. As programmers, we are supposed to come up with solutions that meet the following criteria:

  • meet the functional requirements; eg perform as required without bugs,
  • are delivered within the mandated timeframe,
  • are maintainable; eg the next developer can read and modify the code,
  • performs fast enough for the task in hand, and
  • can be reused in future tasks.

(These criteria are roughly ordered by decreasing priority, though different contexts may dictate a different order.)

Inventiveness is NOT a requirement, and "avoid[ing] redundancy or repetition of any kind" is not either. In fact both of these can be distinctly harmful ... if the programmer ignores the real criteria.

Bringing this back to your question. You should only be looking for alternative ways to do singletons if it is going to actually make the code more maintainable. Complicated "inventive" solutions may well return to bite you (or the people who have to maintain your code in the future), even if they succeed in reducing the number of lines of repeated code.

And as others have pointed out (eg @BalusC), current thinking is that the singleton pattern should be avoided in a lot of classes of application.

There does exist a multiton pattern. Regardless, I am 60% certain that the real solution to the original problem is a RDBMS.

@BalusC is right, but I will say it more strongly, Singletons are evil in all contexts. Webapps, desktop apps, etc. Just don't do it.

All a singleton is in reality is a global wad of data. Global data is bad. It makes proper unit testing impossible. It makes tracing down weird bugs much, much harder.

The Gang of Four book is flat out wrong here. Or at least obsolete by a decade and a half.

If you want only one instance, have a factory that makes only one. Its easy.

如何将参数传递给创建单例的函数(例如,它的名称或特化),知道为每个唯一参数创建单例?

I know you asked about Java, but here is a solution in PHP as an example:

abstract class Singleton
{
    protected function __construct()
    {
    }

    final public static function getInstance()
    {
        static $instances = array();

        $calledClass = get_called_class();

        if (!isset($instances[$calledClass]))
        {
            $instances[$calledClass] = new $calledClass();
        }

        return $instances[$calledClass];
    }

    final private function __clone()
    {
    }
}

Then you just write:

class Database extends Singleton {}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM