4 ms·
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 b
by lazydon 13y ago
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.
http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ 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/25/root-cause-of-singletons/
http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/ http://misko.hevery.com/2008/08/21/where-have-all-the-single...
I miss this guy in Java world.
- brown9-2 13y agoI 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?".
- ehutch79 13y agowait. isn't angular full of singletons? I mean that's what a service is in angular. I just wrote like three of them.
- supermatt 13y agoAs 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.
- seanalltogether 13y agoSomething is bugging me about the examples he's using there, I've never seen singletons used that way. these are just static initializers. testCreditCardCharge() { CreditCardProcessor.init(); CreditCard c = new CreditCard( "1234 5678 9012 3456", 5, 2008); c.charge(100); } Instead I would expect a singleton to be used this way. Which takes care of initialization where its needed. class CreditCard { private number; function charge(amount){ processor = CreditCardProcessor.getInstance(); processor.go(number, amount); } } I'm not saying this is better way to process this datamodel, but it is the correct way to use a singleton.
- jdmichal 13y agoThere's not really a whole lot of difference between this: processor = CreditCardProcessor.getInstance(); processor.charge(number, amount); And this: CreditCardProcessor.charge(number, amount); 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.
- seanalltogether 13y agoBut 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 CreditCardProcessor.init() CreditCardProcessor.charge(number, amount); and CreditCardProcessor.getInstance().charge(number, amount);
- jdmichal 13y agoSolve 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.
- pmelendez 13y ago>"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.
- jdmichal 13y agoI 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.
- l0u 13y agoI 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.
- benihana 13y ago>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.
- masklinn 13y ago> 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"?
- srj 13y agoHonest 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. Do you know of a better way?