I have an UI
module that will expose only one class - UserInterface
. The class will be responsible for collecting user input and providing output (command line UI style). From logical way of thinking, I'd never need more than one instance of the UserInterface
class.
Should I enforce only one instance using design like singleton pattern or just don't create more instances (sounds like a bad design to me)?
2 Answers 2
A singleton for your UserInterface
makes only sense when all of the following conditions are met:
having more than one instance cannot be allowed, because that would cause a misfunction in the program if two of those objects exist at the same time
you know for sure you will never need inheritance for
UserInterface
.
If not both conditions are met, a singleton is either unsuitable or overdesigned. This is pretty often the case in real-world scemarios, that's why Singleton is often considered to be an anti-pattern.
Note also that when there are components depending on the "singleton candidate", passing the latter by constructor injection into the components / classes may simplify unit testing. By this kind of design, it does not make a huge difference if the injected object is a singleton or not. In case all the depending components are implemented that way, the "singleton mechanics" is probably not worth the hassle, since you can make sure there is only one object of the "singleton candidate" in "wiring up" part of the program.
-
what to do if I need unit tests and having more than one instance would break the application? I guess I'll have to design
UserInterface
some other way in order to prevent it from doing any "damage" if instantiated twice or soWiktor– Wiktor2021年05月14日 12:00:33 +00:00Commented May 14, 2021 at 12:00 -
@Wiktor: to be fair, a component which requires the single instance can be designed to be unit-testable even when the single-instance is a singleton. The component should just not make use of the Singleton mechanics to get the instance, but injected from outside. But when all users of the singleton get the instance injected, the classic Singleton mechanics becomes pretty useless.Doc Brown– Doc Brown2021年05月14日 12:45:05 +00:00Commented May 14, 2021 at 12:45
-
it's worth noticing that singleton doesn't have to be a class/interface with public static access. It could also be designed as a class with a static boolean
hasBeenCreated
check in the constructor (if true it could throw an exception)Wiktor– Wiktor2021年05月14日 14:35:25 +00:00Commented May 14, 2021 at 14:35 -
@Wiktor: if a component uses
x=MySingleton::getInstance()
orx=new MySingleton()
inside is not a huge difference in regards to unit testing that component (both variants make unit testing harder). If the component expects a single instance ofUserInterface
through its constructor, whereUserInterface
is actually an interface to the expectedUserInterfaceImplementation
object, then it will be easier to exchange theUserInterface
by a mock for testing purposes.Doc Brown– Doc Brown2021年05月14日 15:18:45 +00:00Commented May 14, 2021 at 15:18
Don't use the singleton pattern. Ever. Just create one instance in some central place, like the main()
method and pass that around.
If you are concerned people might instantiate your object in some other way and mess with the rest of your sytem, there are a couple of options: Either make sure it works regardless how it is instantiated, and/or make sure the parameters it needs to mess with the rest of the system are hidden and not readily available. There may be other options.
-
isn't the purpose of a singleton simply to "Just create one instance in some central place" (and also does so via lazy loading)?Peter M– Peter M2021年05月13日 13:05:15 +00:00Commented May 13, 2021 at 13:05
-
I agree that in typical desktop and server development the Singleton pattern is almost never useful. But e.g. when working with hardware/low level code I think it is well suited. E.g. you only have one motor connected to a microcontroller. In that microcontrollers code there is no use for more than one instance of a controller class for that motor. You don't want two to accidentally have two instances sending conflicting commands, leading to damage to physical things. So I wouldnt paint it this black-and-whitemarstato– marstato2021年05月13日 13:35:27 +00:00Commented May 13, 2021 at 13:35
-
@PeterM My wording was maybe a bit imprecise. Singletons are looked up every time they are used. So while they are "at" a single place, or the code used to look it up is at a central place, the lookup/usage is not. Does that make more sense?Robert Bräutigam– Robert Bräutigam2021年05月13日 13:58:20 +00:00Commented May 13, 2021 at 13:58
-
@marstato Even if you have a singleton motor controller, that doesn't really prevent you using the pins elsewhere, right? In my (hobby) arduino projects, I just declare all the hardware in one place, so I can see the pins I use at one glance. If you don't want to do that, you can always use some additional objects to manage the pins, make sure there are no conflicts, and require all hardware objects to get pins from that object.Robert Bräutigam– Robert Bräutigam2021年05月13日 14:04:57 +00:00Commented May 13, 2021 at 14:04
-
@RobertBräutigam It's a trade off between a function call to get a pointer vs passing a pointer down through every function that might use it or need to pass it on to another function that will use it. The latter pollutes the function call hierarchy with irrelevant information. But the function call efficiency hit can be minimized by using an IoC approach in the classes that actually need to use the UI module.Peter M– Peter M2021年05月13日 15:18:49 +00:00Commented May 13, 2021 at 15:18
Explore related questions
See similar questions with these tags.