2

So I'm rather new at OO Design, and I'm wondering about the use of the Singleton design pattern. I've read some articles about why singletons are bad but still can't figure out if I could need one or not. I'd like to avoid it as much as possible.

In my case, I work with OceanOptics Spectrometers, that can be controlled and consulted through their API, in C++.

I've put all the code that manages spectrometers (discovering them, setting or getting parameters, retrieving data) in a single class SpectrometerProxy.

And I would like to know if this class should be a singleton or not. I feel that there might be a few reasons that could justify it:

  • It manages hardware

  • Whatever the number of spectrometers, they're all controlled and consulted through this class

  • There's a specific procedure that must be done in a precise order, and only once (opening spectrometers, checking some variables, and closing spectrometers when the program stops)

Then, I don't know if there are better ways of implementing this class than making it a singleton. The other solution I thought of was keeping it as a normal class but prevent copying (by declaring copy constructor and assignment operator private) and just passing a pointer to the classes that need it : it would not prevent the creation of multiple SpectrometerProxy and I'd like to avoid that.

I also thought of making it all static, but then it would rely on the client code to call the correct static member functions in the correct order (and not forgetting to close correctly the connections to spectrometers), and thus would be error-prone and contrary to the RAII principle.

So, would a singleton be a possible correct design approach for this problem, or should I exclude it and search for other ways ?

Community
  • 1
  • 1
JBL
  • 12,588
  • 4
  • 53
  • 84
  • 1
    Short answer: "no". Longer answer: "why would you?" – jalf May 13 '13 at 09:59
  • I know that I shouldn't. I've read on why singleton are bad. The "Why would you ?" is quite my question. The other part is "What are the possible alternatives ?". Thanks. – JBL May 13 '13 at 10:07
  • 1
    Today, you think you want to control all your spectrometers through a single proxy. Tomorrow, you might want more than one independent proxy. That will be more difficult with a hard-coded assumption that there is only one. – Mike Seymour May 13 '13 at 10:31
  • @MikeSeymour : That's a really good point indeed. I thought I'd need to handle the fact that I'd have to handle more than one spectrometer (though for the moment there is only one), but I didn't think of the fact that I could need more than one _proxy_ . – JBL May 13 '13 at 10:34
  • Imagine it isn't possible to implement a singleton in C++. Is your job now significantly worse? – Peter Wood May 13 '13 at 10:43
  • Why do you think you need to prevent the creation of multiple proxies? Do you often *accidentally* create new objects? Do you create new `std::ostream` objects when you meant to write to `std::cout`? If you only need one proxy (for the moment), just create one proxy, and prefereably pass it to the objects that needs it, but alternatively, make it globally accessible. But don't make it *impossible* to create another proxy – jalf May 13 '13 at 11:03
  • By the way, some more reading material for you: http://jalf.dk/singleton/ :) – jalf May 13 '13 at 11:04
  • @jalf Well, I would be sure to not create multiple proxies (it performs actions that must be done in a specific order/only once). But what if my code ends up being taken over by another dev ? Shouldn't I be concerned that my code is hard to use incorrectly ? – JBL May 13 '13 at 11:19
  • @JBL sure, but you also have to assume that he's going to be competent (otherwise, he'll screw up no matter what you do). Just like you, he isn't going to start creating arbitrary objects just for the fun of it. If he can see in your code that you consistently use the same proxy, he will copy that. And if you document/comment the code, or just name the object and class appropriately, he'll also be able to understand (1) whether creating a new proxy is the right thing to do, and (2) whether it is safe to create a new proxy. – jalf May 13 '13 at 11:29
  • But keep in mind that while *you* can't see a need for another proxy, that doesn't mean that creating two proxies is *incorrect*. It might be, or it might not. That depends on what the developer is trying to achieve. A singleton makes it hard to use the code *for anything that you hadn't anticipated when you wrote it*, which is a bad thing. If you want to make it hard to use the code correctly, then ensure that it'll *work* if I create more than one proxy. Then I can decide how many to create based on my *need*, rather than on what makes the code blow up. – jalf May 13 '13 at 11:33
  • @jalf I think you've summarized quite well why a singleton would be a very bad idea regarding code evolution/extension, with "A singleton makes it hard to use the code for anything that you hadn't anticipated when you wrote it". Actually, I didn't find that in the articles about the cons of singletons. – JBL May 13 '13 at 11:37

3 Answers3

4

It's mostly a religious theme: to use or not to use singletones. According to my experience for working with hardware (10+ years) I'd prefere NOT to use them. First: as Murphy's law says tomorrow you'll need to work with more then one Spectrometers. Second: it's better to make a virtual abstract interface with methods you need to interact with hardware, inherit from it and write a code, that actualy deals with hardware. This way is useful when you do not have an access to hardware but you need to debug your app. In this case you just subclassing that interface and making emulating functions (or better functions, that read actual data from previously recorded file with data, got from the hardware), but the rest of your program stay unchanged.

borisbn
  • 4,988
  • 25
  • 42
  • 1
    Thanks for suggesting the virtual abstract interface. It feels quite obvious and simple, yet I didn't think of it. That will be useful as I don't always have access to Spectrometers to test. – JBL May 13 '13 at 10:09
2

I think the question you should be asking yourself is why you need a singleton class other than you suspect that in any location you would only have one spectrometer (due to cost for instance) in which case it is more coincidently a singleton than for any software design reasons. Why you might want a singleton is covered in On Design Patterns: When to use the Singleton? and the negative aspects of singletons are covered in What is so bad about singletons?. Personally I am not a big fan of the singleton patter except where the situation actually demands it from a software perspective, anything else could lead to future code re-factorings.

Community
  • 1
  • 1
OOhay
  • 61
  • 6
1

Besides singleton decision, I believe that having a single class to discover the equipment and controlling individual devices is a bad idea - you are putting different functionality into same class for no apparent reason.

It is hard to say without knowing more, but in general it might make more sense to split the functionality into separate classes:

  • HwLookup - performs device discovery etc. This might be a singleton, but I am not sure I would do it - I don't see any particular reason to make it singleton but it might make sense. It returns individual instances of
  • SpectrometerProxy (or just Spectrometer) which represents a single device and can be used to set/get parameters, retrieve measurement results etc)

Depending on how much stuff it does, I am not even sure if I would design HwLookup as a class: it can be a function (e.g. if all it does is return a list of spectrometer proxies). There is no reason to put everything into class in c++ code.

Zdeslav Vojkovic
  • 14,391
  • 32
  • 45
  • Well, I kind of like the idea of a Hardware lookup class that returns "instances" of devices, but in my case, I need to invoke a function that opens all spectrometers, and when the program shuts down, a function that closes all spectrometers (it releases them). These two steps must be done once and only once. Thus the idea of using a singleton at least for the harware lookup and management that would perform these steps automatically on start-up and on shutdown. – JBL May 13 '13 at 10:03