How to avoid singletons when making an OOP state machine design?
Asked Answered
P

3

8

I'm in the midst of trying to teach myself programming. I started the same way that I'm sure most people start; making small, messy apps and games that do simple things in not-so-simple ways. Recently, I've been trying to take the next step by writing a slightly more complex game that uses OOP design to write better, more modular code!

The main issue I've been having is the design of my main StateManager (FSM) class (to switch between intro/menu/game/etc screen states). I've looked high and low, and I've only really seen two methods of designing them:

  • Use a switch/case statement + an enum to switch between states..

  • Make a singleton FSM class that handles pushing/popping states to/from a vector..

Now, my problem is, the switch case statement is very repetitive and clunky, and it kind of works against my goal of using this project to teach myself OOP.

My second, and bigger problem is the 'singleton' suggestion.

As I said before, I'm trying to teach myself, and I still have a lot to learn when it comes to programming, especially in the field of OOP and design patterns and all that stuff. I've run into an issue where, for EVERY single 'singletons are evil' thread and discussion that I find, I find just as many tutorials and references where people use singletons in their code to make 'engine' classes and FSMs. It's a very consistent mixed message.

I suppose I just don't understand why... Even if you only want/intend to have a single object of a class, why is it necessary/beneficial to make the constructor private and create a singleton? I've read a lot about how singletons are bad, how they are essentially global, how they get in the way of multi-threading, and how many programmers consider them overused or just plain bad design... Yet I see example after example of people using them, and very few counter examples showing alternate methods.

Couldn't the same type of thing be done with just a regular class? What's the purpose of explicitly restricting the creation of instances? I've heard only negative things about singletons, yet people seem to use them constantly... Am I completely missing something about singletons and OOP?

Is the use of singletons just a trend, or is it just a trend when people call singletons 'evil'? How do I get around this..? Isn't there something between the switch/case FSM and the singleton FSM?? Couldn't someone design their program's state system the exact same way without making any of their classes singletons? Would that change something? [confused]

Plutocracy answered 9/8, 2012 at 11:13 Comment(2)
A third option might be to use an external tool to generate FSM class boilerplate code for you (I wouldn't recommend plain old C/C++ macros, though they might work). I believe there are already tools that will do this for you if you didn't fancy crufting together your own out of perl or whatever. Lots of folk seem quite adverse to this sort of code generation step, but it can save quite a bit of effort and repetition.Snort
I never considered that. Any recommendations? I'm not sure how to go about doing that or what tools to use. - Although, I'd really like to get learn how to do it myself to.. I'd really like to get the hang of OOP and FSMs for the sake of learning. :) Good advice though, thank you.Plutocracy
M
6

Couldn't the same type of thing be done with just a regular class? What's the purpose of explicitly restricting the creation of instances? I've heard only negative things about singletons, yet people seem to use them constantly... Am I completely missing something about singletons and OOP?

No, I believe you're on the right track: there's absolutely no reason to prevent the creation of two instances. The Universe won't implode because of that.

It's a completely unnecessary restriction. Since you have to manually code that restriction, it's quite silly to have it at all (if you had to write code to lift it, that would be another matter).

I suppose there may be weird and rare situations where the Universe does implode if a second instance is created, but that sounds quite farfetched. In any case, it doesn't justify the prevalence of singletons all over the Internet.

I can't really explain why people use them constantly without insulting the reasoning abilities of those people, so I will refrain from doing so.

Couldn't someone design their program's state system the exact same way without making any of their classes singletons? Would that change something?

The only thing it changes is that by making it a singleton you prevent yourself from creating throwaway instances for unit testing. Everything else just works the same.

Mercedes answered 9/8, 2012 at 11:19 Comment(8)
Even if a second instance causes the universe to implode, that doesn't necessarily mean you need universal access to that one instance too, which is what most people seem to forget about singletons.Waxwing
They are used, because they were (or are) a design pattern and people tend to use them because they are design patterns. But they should only use them when they are justified (which in most cases they are not). To phrase it more generally: Design patterns (especially the singleton) are overused.Contemporary
Thanks for the answer, that was fast! I'll be the first to admit, right now I'm an uneducated noob programmer, trying to figure out what the hell I'm doing! I've been researching over and over trying to learn more and get better to the point where I can actually begin to create things and do the cool stuff that all programmers like to do! I've seen so many singletons all over the place, and at the same time I've pretty much only seen reasonable evidence why singletons are bad design and unjustified. I've never once seen a concrete example of a class that NEEDS to be a singleton. Thanks! ^^Plutocracy
@MrKatSwordfish: Filesystem; that's generally the classic example. But generally, when you see someone suggesting that something be a singleton, ask yourself, "why does one need to prevent someone from instantiating a second one?" Most of the time, "singleton" is confused with "globally-available instance".Margenemargent
@Plutocracy for an "uneducated noob" you already show one of the most important qualities: you think for yourself and don't do things just because you read them on the Internet. Keep doing what you're doing :) Oh, and welcome to Stack Overflow!Mercedes
I can give one real-life example -- one that, admittedly, backfired! In the (Qt framework)[http://doc.qt.nokia.com/], the QCoreApplication is a singleton, but behind the scenes it creates some other threading-related singletons. It makes hard to start the Qt framework in a non-default thread, even though the underlying platform APIs otherwise place no such restrictions. So, sometimes even if it "obviously" would make sense, you may be less-obviously but nevertheless quite impactfully wrong.Mcgrath
Haha... thanks! Although you might agree with me if you saw my code! xD Thanks for the warm welcome to Stack Overflow, this type of resource is amazing and wonderful, especially for people like me who have never had a programming class or teacher. It's a great thing, the internet! :) I had a gut feeling not to trust singletons, and I'm glad I asked because now I can feel assured that I'm not missing something important... hahaPlutocracy
There are cases where a second instance of a class in a single process would be a serious error. This clearly isn't one of them, however. And I think Nobody's answer is the probable explication as to why they are overused. They're one of the simplest design patterns to understand, so people use them to say that they're using design patterns. Even if they don't understand the motivation behind the pattern.Rimple
R
3

As is often the case, there is no one simple answer. In C++, the singleton pattern also manages order of initialization issues, which are important if it is to be used in the constructors of static objects. And there are certain types of objects where multiple instances can only be a programming error; if you can prevent them, why not.

On the other hand, I have a great deal of difficulty imagining a case where a StateManager class should be a singleton. It is in no way managing some unique resource, or some meta-functionality (e.g. like logging) which by its very nature must be unique. And I can't imagine it being used in the constructors of static objects either.

A statement such as "singletons are bad" is very misleading; for some things, they are the most appropriate solution. But just because they aren't bad in the absolute doesn't mean that they are appropriate everywhere. They solve one particular, very limited problem. When you need to solve that problem, not using a singleton is bad. But (as is true for just about everything), using it when it isn't appropriate is bad.

Rimple answered 9/8, 2012 at 12:9 Comment(0)
H
1

I don't see why the FSM class should be a singleton. There are plenty of real-world FSM systems where there are no singletons, heck, there are some where the state instances are created and destroyed as the SM traverses the states, and where the state machine is itself a state to enable easy composability of hierarchical state machines.

In a complex application, you will have multiple state machines, some of them popping in and out of existence. The ones that handle, for example, client-server interaction, will necessarily have multiple instances that come and go with clients. Some others may benefit from composing multiple hierarchical state machines, some of which may be re-used in many places. Thus the idea that you'd have a state machine as a singleton class is silly to me. You may have, for example, an instance of a particular state machine in a singleton application class that encapsulates your application, but that's far from having a singleton class state machine.

To get a good overview of various state machine implementation techniques, including contrasts between flat FSMs and hierarchical state machines (HSMs), you'd want to get a look at Miro Samek's PSICC2 book. He has plenty of freely downloadable articles where common techniques are explained.

A reasonable C++ implementation of a hierarchical state machine, usable for UI, is available in the state machine framework in Qt.

Horsepower answered 9/8, 2012 at 11:50 Comment(2)
Thanks for the insightful response and the references! One thing that bothers me still is: even assuming that the programmer is creating a class that they only intend to have a single instance of, is there really any point of turning that class into a singleton? (as opposed to just simply, choosing not to create any other instances..?) Thanks again!Plutocracy
Not, as long as you don't break things by creating multiple instances. If the class has to claim some resources that logically can only be claimed once, then the singleton pattern enforces that use case and prevents errors. Otherwise it's pointless.Mcgrath

© 2022 - 2024 — McMap. All rights reserved.