Singletons are always a lazy solution to the problem. For me the rule of thumb is if there's some class requiring lots of work to test, I've been lazy. So, go back and review my sloppiness.
The questioner was in a way implementing a poor man's cache using Singletons (I wonder how was he planning to test it); some use it for connection pooling instead of a specific library.
I've heard even GoF regretted including Singletons in the s/w patterns club.
I'm a big fan of Misko Hevery's (now working on Angular) work on this.
>"For me the rule of thumb is if there's some class requiring lots of work to test, I've been lazy."
Unit tests are great, but when they get in the way I always look it as a chicken and egg paradox. Is my simple and easy to maintain code inferior because it is not test friendly? Or is the test friendly alternative inferior because is more complex and harder to maintain?
And this haven't happened to me just with singletons, sometimes unit tests just like to get in your way.
I find the biggest barrier to unit tests is not noticing when it's more appropriate to create a public static function (probably on another class) instead of a private one. If a private method is so complex that you cannot appropriately test it using the public interface, then it really needs to be its own entity.
I could be a bit off base, and to be honest am only now coming to grips with unit testing fully, but I find if something is painful to test my implementation wasn't good to begin with. I'm guessing this is where writing tests first really comes in handy as you have to implement in the right way from the start.
The only difference is whether the state of the CreditCardProcessor is stored statically on the class, or is stored in one magical instance. They will both have the exact same pathology in the code and during testing. The former will be slightly easier to refactor, since at least it's already based on instances.
But the whole point of the singleton pattern is to solve these exact issues. To enforce a single entry point that is 1. Lazy evaluated to ensure initialization.
2. Preferably locked to solve threaded access.
3. Instance based to ensure you are manipulating an object vs truly static variables.
I honestly think there's a huge potential difference between
Solve what issues? I did not mention any issues. I see no difference between the two, other than one basically enforces initialization by gating it through a "getInstance" call. (And thereby also enforcing an additional function-call penalty on every functionality presented. Nothing is free.) I could do the same, with the same trade-offs, by simply invoking init() at the start of every method call.
To address your points specifically:
1. Whether the item is lazily initialized or not is an implementation detail. In fact, the call of "init" on the first format is lazy initialization; an eager initialization would have completed at class-load.
2. Either method can implement exclusionary locks. There is no difference here.
3. This is the big difference between the two, but you write it as if it's a benefit unto itself. From an API perspective, why do I care whether I'm manipulating an variables that live on an object instance or statically on the class?
Here's an exercise. How would you even know whether the code to a Singleton class looks like this?
class SomeNumber {
private static Integer value;
public static SomeNumber getInstance() {
if (value == null) value = 5;
return new SomeNumber();
}
public Integer getValue() {
return value;
}
}
If you cannot tell whether the Singleton class was implemented this way from the external API, then there is no difference between the two implementations.
Invoking init at the start of every method call won't be caught by the compiler if you forget to do it in one spot. Static safety is usually a win - on a big project, someone will do something wrong and it's best if it's caught right away when they try to compile.
I've actually been wanting ways of enforcing arbitrary rules on the structure of my code at compile time...
Honest question as I'm wondering if I could have done something differently.
I have a third-party library that has expensive initialization done inside of its class's parameterless constructor. Once created the library's instance is fully thread safe. Because I only wish to incur the initialization cost once I have a straightforward singleton to wrap the instance:
GetInstance():
hold mutex
if instance is null:
instance = ExpensiveLibraryConstructor()
return instance
Now the code I'm writing code plugs into a framework I don't control. I create a class that conforms to the framework's client interface and the framework creates instances of my class and calls a Run() method. My Run() method needs to be able to make use of the third-party library, so I'm calling my singleton's GetInstance() method there.
Not that it would make much practical difference but ExpensiveLibraryConstructor() needs some environment initialization done before it will succeed so I cannot invoke the constructor in global scope.
I really loved Misko's blog back in the day, and these are the exact articles I always quote to people when they ask "why is the singleton pattern a bad thing?".
As the author would say: singletons (single instances), yes. Singletons (as in the pattern), no. In his articles, it appears that he uses the word 'singleton' to mean 'Singleton' though, which is mildly annoying.
>Singletons are always a lazy solution to the problem
The fact that you said x is always y in programming is troubling. Sure singletons are usually a lazy solution, but saying there isn't a single case EVER where a single is the proper solution is ridiculous.
> saying there isn't a single case EVER where a single is the proper solution is ridiculous.
Is it? Some things are simply mistakes to and through. Consider nailing your penis to a table, is it ever the right solution to anything, aside from "how could I get my penis nailed to a table"?
The questioner was in a way implementing a poor man's cache using Singletons (I wonder how was he planning to test it); some use it for connection pooling instead of a specific library.
I've heard even GoF regretted including Singletons in the s/w patterns club.
I'm a big fan of Misko Hevery's (now working on Angular) work on this.
http://misko.hevery.com/2008/08/17/singletons-are-pathologic...
http://misko.hevery.com/2008/08/25/root-cause-of-singletons/
http://misko.hevery.com/2008/08/21/where-have-all-the-single...
I miss this guy in Java world.