views:

1304

answers:

11

It's understandable that many design patterns can in some cases be abused, and like mom always said: "Too much of a good thing isn't always good!"

I'm noticing that these days, I'm using Singletons a lot, and I'm worried that I might be abusing the design pattern myself, and running deeper and deeper into a bad-practice kind of habit.

We're developing a Flex application that has a quite a large hierarchical data structure kept in memory while the user works on it. The user can load, save, change and refresh the data on demand.

This data is centralized by means of a Singleton class, which aggregates a couple of ArrayCollections, Arrays, value objects and some other native member variables exposed via getters and setters.

To get a reference to our data from anywhere in the application, we do the whole Model.getInstance() method type of thing, that I'm sure everyone is familiar with. This ensures that we always get our hands on the same copy of data, since when we designed, we said that only once instance is allowed to exist during the application lifetime.

From this central data repository, it's then easy for us to for example, dispatch property changed events, and can have multiple UI components that reference the central data, update their displays to reflect the data changes that have occurred.

So far, this approach has been effective and proven very practical to our circumstances.

I'm finding however, that I'm a little overeager when creating new classes. Questions like should a class be a Singleton, or should it rather be managed some other way, like maybe using a factory for example, tend to sometimes become a bit difficult, with a bit of uncertainty.

Where do I draw the line with singletons? Is there a good guideline for deciding when to use Singletons and when to stay away from them.

Also, can anyone recommend a good book on design patterns?

A: 

No, they're not necessarily bad.

As for a book, you need to start with the classics.

Stu
+12  A: 

The key thing to remember is that design patterns are just a tool to help you understand the abstract concepts. Once you have that understanding, restricting yourself specifically to a "recipe" from a book is pointless and hurts your ability to write the code most appropriate for your purpose.

That said, reading books like GoF will present you with more ways to think about problems so that when the time comes to implement something on your own, you'll have a wider set of perspectives to approach the problem from.

In your case, if using singleton makes sense in every case, then go right ahead. If it "sort of" fits and you have to implement it in some clunky way, then you need to come up with a new solution. Forcing a pattern that isn't perfect is somewhat like hammering a square peg in a round hole.

Given that you say "this approach has been effective and proven very practical to our circumstances," I think you're doing fine.

Here are some good books:

Gang of Four Book - the classic book for design patterns

Head First Design Patterns - I've heard this recommended by a few people as an alternative

mandaleeka
Thank you all so much!!! I'll definitely get a copy of at all these books, and work my way through them. I think I've heard about the "Gang of Four Book" somewhere.
Joe Zephyr
Most of the rest of the GoF book is fine, but on the subject of singletons, I seriously think they must have been smoking something illegal. Either that, or it was a concession to old procedural programmers (who really want their globals), in order to win them over to OOP ("Hey look, you can make globals in OOP too! We just call them singletons")
jalf
Yeah, I'll second what jalf says, beware of using singletons as just a oop version of global variables.
Simon P Stevens
A: 

Singletons are not "that bad". If you have a lot of related Singletons and you can replace/consolidate a number of them using a Factory, without losing anything you care about, then that's when you should so do.

As to books, well, there's kind of a canon.

chaos
A: 

I thought singletons were good.

Jeff Meatball Yang
+2  A: 

Singletons don't kill programs, programmers kill programs.

Like any programming construct, when used appropriately, you will not shoot yourself in the foot.

The books recommended are fine, but they don't always give enough background that comes with experience on when you might make the choice to use Singleton.

That experience only comes when you've found Singleton is a bad choice when you need to have multiple instances, and all of a sudden, you've got a lot of trouble injecting the object references everywhere.

Sometimes it's better to go ahead and have the object references in place, but the fact that you are using Singleton at all does help to identify the scope of the problem you would face if you had to refactor it to a different design. Which I believe is a very good thing: i.e. just having a class at all (even if poorly designed) gives some ability to see the effects of a change to the class.

Cade Roux
+1  A: 

Practicality is what counts, patterns and rules that do not definitively solve your problems are nothing to cry about!

BakerTheHacker
+1  A: 

Singletons are certainly not bad. They have their uses, some of them very good. Singletons do tend to be overused by inexperienced developers as it's often the first design patten they learn about, and it's fairly simple, so they chuck it around all over the place without thinking about the implications.

Every time you want to use a singleton, try to consider why you are doing it, and what are the benefits and negatives of using this pattern.

Singletons do effectively create a global accessible set of 'stuff' (either data or methods) and I think most people would agree that using too many global variables is not a great idea. The whole point of classes and object orientation is to group things into discrete areas rather than just chucking everything into one massive global space.

One of the 'patterns' I find I tend to prefer over singletons is to pass needed objects down from the top. I create them once during my apps initialization phase, and a pass them down through all the objects that need access to them. It mimics the 'single-creation' part of a singleton pattern, but without the 'global' part.

The whole point of a singleton is that it's for objects where only 1 should ever exist. You mention a data control set of classes. Perhaps consider that actually, there are cases where an app might want to create 2 sets of data control classes, so perhaps enforcing a singleton on this isn't quite right. Instead, if you created these data classes on app init, and passed them down, you would be only creating 1 set as that is what you current app requires, but you leave open the possibility that at some point, if you need a second set you can easily create them. Also, should data control classes really be accessibly globaly from anywhere in the app. I think not, instead they should probably be only accessible from a lower level data access layer.

Some people have recommended the GOF book. I would say, yes that is a great book, but first try and find a book on general architecture first, read about 2/3/n-tier design, encapsulation, abstraction, and these kind of principles first. This will give you a more solid base with which to understand the appropriate usage of the patterns the GOF talk about.

[Edit: The other time that a singleton variant can be useful is when you want a single access point to something, but the implementation detail might actually be more than one thing. The caller doesn't need to know, that under the covers their request for the singleton object is actually resolved against several available objects and one is returned. I'm thinking of something like a thread pool here, where the use goes, hey, just get me a thread, I need 1, but I don't care which one]

Simon P Stevens
The thread pool is a great example of singletons backfiring. The .NET thread pool works like that, and it is a pain. It means I can't create a thread pool for tasks in my application. I have to share it with the .NET class library, any third-party libs I might be using, and god knows what else. I have absolutely no way to tell how likely it is to even *have* a free thread. A sane design would be to make a thread pool class that *anyone* can instantiate if they want their *own* thread pool, and then expose a single global thread pool we can use when we don't care how many other users exist.
jalf
@jaif: I feel like you've missed the point of he threadpool. It's there for very quick simple dirty tasks that you want done off the main thread, if you care about getting a free thread or if you want more control you can use the Thread class, or the BackgroundWorker. If you want your own personal user managed pool of threads you can look at implementing a producer-consumer pattern (see half way down this page: http://www.albahari.com/threading/part4.aspx). The whole point of the thread pool is that it's meant to balance async work across the whole system, not just your app.
Simon P Stevens
Why should *I* have to implement this pattern myself, when .NET already tried to do it for me? The point is that if they had not hard-coded it as a singleton, it would have done the job across the whole system that it does not, *in addition* to being useful in smaller scopes within my own app. It is a perfect example of singletons removing flexibility for no reason. I'm not missing the point of the thread pool, I'm saying that with a tiny modification, it would have been far more generally useful.
jalf
If you created multiple thread pools how would they balance themselves.I think what you want is something different.I can't see how multiple thread pools would work.The thread pool *is* a system wide pool of threads,that is there to balance work across apps,and there *is* just one of them,so a singleton is appropriate way of accessing it.Yes, perhaps MS should implement a producer-consumer thread queue as well,but they can't provide for everything.Anyway, lets not argue too much about it,I'm sure MS have their reasons for doing it the way they did,we have to live with that for good or for bad.
Simon P Stevens
+19  A: 

Yes, singletons are bad. They are bad because all they do for you is combine two properties, each of which is bad about 95% of the time. (Which would mean that on average, singletons are bad 99.75% of the time ;))

A singleton, as defined by the GoF, is a data structure which:

  1. Grants global access to an object, and
  2. Enforces that only one instance of the object can ever exist.

The first is generally considered a bad thing. We don't like globals. The second is a bit more subtle, but generally, there are virtually no cases where this is a reasonable restriction to enforce.

Sometimes, it only makes sense to have one instance of an object. In which case you choose to create only one. You don't need a singleton to enforce it.

And usually, even when it "makes sense" to have only one instance, it turns out not to make sense after all. Sooner or later, you're going to need more than one logger. Or more than one database. Or you're going to have to recreate resources for each of your unit tests, which means we have to be able to create them at will. It is prematurely removing flexibility from our code, before we understand the consequences.

Singletons hide dependencies and increase coupling (every class can potentially depend on a singleton, which means the class can not be reused in other projects unless we also reuse all our singletons), and because these dependencies are not immediately visible (as function/constructor parameters), we don't notice them, and typically don't think about it when we create them. It's so easy to just pull in a singleton, it acts almost as a local variable and all, so we tend to use them a lot once they're there. And that makes them almost impossible to remove again. You end up, perhaps not with spaghetti code, but with spaghetti dependency graphs. And sooner or later, your runaway dependencies will mean that singletons start depending on each others, and then you get circular dependencies when one is attempted initialized.

They make it extremely hard to unit-test. (How do you test a function that calls functions on a singleton object? We don't want the actual singleton code to be exercised, but how do we prevent that?

Yes, singletons are bad.

Sometimes, you really want a global. Then use a global, not a singleton.

Sometimes, very very very rarely, you may have a situation where creating multiple instance of a class is an error, where it can not be done without causing errors. (About the only case I can think of, and even that is contrived, is if you're representing some hardware device. You only have one GPU, so if you're going to map it to an object in your code, it would make sense that only one instance can exist). But if you find yourself in such a situation (and again, for emphasis, a situation where multiple instances cause serious errors, not just a situation where "I can't think of any use cases for more than one instance"), then enforce that constraint, but do it without also making the object globally visible.

Each of these two properties can be useful, in rare cases. But I can't think of a single case where the combination of them would be a good thing.

Unfortunately, a lot of people have got the idea that "Singletons are OOP-compliant globals." No, they're not. They still suffer the same problems as globals, in addition to introducing some other, completely unrelated ones. There is absolutely no reason to prefer a singleton over a plain old global.

jalf
There are tons of times when enforcing a singleton is a critical idea. Think of a database connection pool. You wouldn't want two separate pools, as you would possibly open connections when there may be some already available.
Kekoa
Why wouldn't I want two separate pools in my unit tests? Why wouldn't I want two separate pools for separate databases? Why wouldn't I want two separate pools if I have two separate tasks that shouldn't be allowed to starve out each other? One task might hog all the connections in its own pool, so I want to reserve some for the other. But even if you *do* absolutely positively want only one pool, why do you need a singleton to enforce it? Do you often *accidentally* create new connection pools? Of course not. If you only need one, just *create* one.
jalf
+1 Couldn't have said it better. Exactly how I feel and educate my fellow colleagues. Many points also apply to the monostate pattern and (ab)use of global static methods.
gix
Issue 1 is the real killer, because it is so hard to fix once you have sprinkled it all over your code.
starblue
Agreed. You'll eventually see the light as you gain more development experience.
Eric Muyser
I wish I could favorite answers (again).
Jeff Sternal
+1  A: 

Google seems to be convinced that Singletons are a bad idea.

That's not to suggest that everything Google does is perfect or that their every opinion is the end of any argument, but they've gone so far as to write this Singleton detector to root them out. Make up your own mind.

duffymo
A: 

In my opinion the use of Singletons directly signals a design flaw. The reason is simply that they allow one to bypass the normal object creation and destruction mechanisms built into C++. If an object needs a reference to another object, it should either pass in a reference to it upon construction or create a new instance of it internally. But when you use a singleton you're explicitly obfuscating the creation and teardown cycle. A related problem is that it is extremely difficult to control the lifetime of a singleton. As a result, many packages which include generic singleton implementations also include clunky object lifetime managers and the like. Sometimes I wonder if these don't exist simply to manage the singletons.

Basically, if you need to use an object in many places, it should be created explicitly at the highest common point in the stack and then passed down via reference to everybody who uses it. Sometimes people use Singletons because they have problems passing multiple args to new threads, but don't fall for this, explicitly define your thread args and pass them to the new thread in the same manner. You'll find that your program flows much cleaner and there are no nasty surprises due to static initialization dependencies or erroneous teardown.

Andy B
A: 

We have started a project where we are basically facing the same question, that is, how to access the model, and especially its root element. The project is not a Flex app, but a play! web app, but that doesn't matter really.

Having a single object unique in the system is fine, the problem is how to access it. So the debate about singleton is related to the notion of dependency inversion (DI), and how to obtain objects.

The main arguments for DI are the following:

  • testability and mocking
  • decoupling object instantiation from usage (which can lead to lifecycle management)
  • separation of concerns

Possible approaches for DI are (see the classic article from Fowler):

  • to pass object around in method parameters
  • service locator
  • DI framework

Under this perspective, the singleton pattern is just a kind of service locator, e.g. Model.getInstance().

But to provide maximum flexibility in face of future changes, the reference to the unique object should be passed around as much as possible, and obtained with Model.getInstance() only when necessary. This will also yield cleaner code.

ewernli