views:

842

answers:

3

I'm looking for a piece of code which behaves a bit like a singleton but isn't (because singleton's are bad :) What I'm looking for must meet these goals:

  1. Thread safe
  2. Simple (Understand & use, i.e. few lines of code. Library calls are OK)
  3. Fast
  4. Not a singleton; for tests, it must be possible to overwrite the value (and reset it after the test).
  5. Local (all necessary information must be in one place)
  6. Lazy (run only when the value is actually needed).
  7. Run once (code on RHS must be executed once and only once)

Example code:

private int i = runOnce(5); // Set i to 5
// Create the connection once and cache the result
private Connection db = runOnce(createDBConnection("DB_NAME"));

public void m() {
    String greet = runOnce("World");
    System.out.println("Hello, "+greet+"!");
}

Note that the fields are not static; only the RHS (right hand side) of the expression is ... well "static" to some degree. A test should be able to inject new values for i and greet temporarily.

Also note that this piece of code outlines how I intend to use this new code. Feel free to replace runOnce() with anything or move it to some other place (the constructor, maybe, or an init() method or a getter). But the less LOC, the better.

Some background information:

I'm not looking for Spring, I'm looking for a piece of code which can be used for the most common case: You need to implement an interface and there won't ever be a second implementation except for tests where you want to pass in mock objects. Also, Spring fails #2, #3 and #5: You need to learn the config language, you must set up the app context somewhere, it needs an XML parser and it's not local (information is spread all over the place).

A global config object or factory doesn't meet the bill because of #5.

static final is out because of #4 (can't change final). static smells because of classloader issues but you'll probably need it inside runOnce(). I'd just prefer to be able to avoid it in the LHS of the expression.

One possible solution might be to use ehcache with a default setup which would return the same object. Since I can put things in the cache, this would also allow to override the value at any time. But maybe there is a more compact/simple solution than ehcache (which again needs an XML config file, etc).

[EDIT] I'm wondering why so many people downvote this. It's a valid question and the use case is pretty common (at least in my code). So if you don't understand the question (or the reason behind it) or if you have no answer or you don't care, why downvote? :/

[EDIT2] If you look at the app context of Spring, you'll find that more than 99% of all beans have just a single implementation. You could have more but in practice, you simply don't. So instead of separating interface, implementation and configuration, I'm looking at something which has only an implementation (in the most simple case), a current() method and one or two lines of clever code to initialize the result for current() once (when it is called for the first time) but at the same times allows to override the result (thread safe, if possible). Think of it as an atomic "if(o==null) o = new O(); return o" where you can override the o. Maybe an AtomicRunOnceReference class is the solution.

Right now, I just feel that what we all have and use daily is not the optimum, that there is a baffling solution which will make us all slap our heads and say "that's it". Just as we felt when Spring came around a few years ago and we realized where all our singleton problems came from and how to solve them.

+3  A: 

The best idiom for threadsafe initialization code (imho) is the lazy inner class. The classic version is

class Outer {
  class Inner {
    private final static SomeInterface SINGLETON;

    static {
      // create the SINGLETON
    }
  }

  public SomeInterface getMyObject() {
    return Inner.SINGLETON;
  }
}

because it's threadsafe, lazy-loading and (imho) elegant.

Now you want testability and replaceability. It's hard to advise without knowing what exactly it is but the most obvious solution would be to use dependency injection, particularly if you're using Spring and have an application context anyway.

That way your "singleton"'s behaviour is represented by an interface and you simply inject one of those into your relevant classes (or a factory to produce one) and then you can of course replace it with whatever you like for testing purposes.

cletus
-1; Does not fit #4
Aaron Digulla
Actually the third paragraph addresses testabbility. Just how spoonfed do you want to be exactly? And you downvote for that?
cletus
I already said that Spring is not an option. I don't want to be spoonfed; I've seen about a dozen different ways for lazy init+override which all have their drawbacks. All I'm looking for is whether someone has a better solution than Spring/Guice/etc.
Aaron Digulla
I downvote because the answer doesn't fit to my question but if you feel so bad about it, I can undo it, no prob. No stress, OK?
Aaron Digulla
A: 

I think one solution you could use is providing a protected method which can be overriden in the test (a solution I've used before for testing legacy code).

So something like:

private SomeObject object;

protected SomeObject getObject() {
   if (object == null) {
       object = new SomeObject();
   }
   return object;
}

Then in your test class you can do:

public void setUp() {
   MyClassUnderTest cut = new MyClassUserTest() {
      @Override
      protected SomeObject getObject() }
         return mockSomeObject;
      }
   };
}

I have to say I'm not overly keen on this pattern as it exposes the protected field where you might not really want it, but it's useful for getting you out of some situations where injection isn't an option

MrWiggles
-1, Does not fit "run once" (new #7, formerly only in the description). I want to avoid calling the code in "new SomeObject()" repeatedly because it is expensive.
Aaron Digulla
Now does lazy initialization.
MrWiggles
+1  A: 

You can use IoC techniques even if you dont use an IoC framework (Spring/Guice/...). And it is in my opinion the only clean way to avoid a Singleton.

Guillaume
Sounds promising. Do you have an idea how a distributed IoC container would look like? An IoC container is basically a synchronized map. How would you move all the necessary logic into a few lines of code?
Aaron Digulla