After careful reading the facts about singletons (the code smell, not the pattern) I wonder:
How can I refactor my code to get rid of them?
Despite almost everyone agreeing that bad singletons are, well, bad, I could not found any practical advice on how to replace them. Either it's very trivial or very hard.
There are some ways I can think of but all of it seem to bloat my code tremendously.
For example let's say I have a "global" AppConfig
class which holds license information about the product and describing the features available to the user.
What I can think of:
AppConfig
instance. (BAD: Impossible for cases where you already have a base class, e.g. forms)setAppConfig
method. AppConfigFactory
which can create AppConfig
instances (BAD: Only shifts the problem to another class)What can I do?
EDIT: Clarification: I have identified a bad singleton in my code. Now I want to refactor my code to remove it. I'm asking for tips and general ideas on how to achive this.
The most important drawback of the singleton pattern is sacrificing transparency for convenience. Consider the earlier example. Over time, you lose track of the objects that access the user object and, more importantly, the objects that modify its properties.
Getting rid of a singleton is extremely easy: create an abstraction and depend on that instead of the concrete Singleton. Once this is done, you'll have to decide if you want to fix all the callers of your class or if you only want to do this locally because you don't have time for that or there are to many callers.
Use Dependency Injection and Inversion Of Control framework - this may require significant refactoring. Then, using constructor or property dependency, ask for the "singleton" - ideally, you don't ask for the whole thing, as by the principle of Demeter, it should only ask for the thing it really needs (in your case the license information).
I try to distinguish between Singleton (the antipattern disguising global variables) and singleton (meaning something you only need one of). A true singleton is created once at the start of the program (or in your factory) and passed to the objects that need it.
You say
Create a global AppConfigFactory which can create AppConfig instances (BAD: Only shifts the problem to another class)
In my view this is actually not bad at all. The client's view is that he asks a factory object for the config he should use. He does not know it is a singleton! At a stroke the singleton-ness is encapsulted in the Factory. [Pragmatically the Factory may well end up as a Singleton itself, but everything has to bootstrap, right?]
Now whether you wrap up the Factory access using Dependency Injection techniques is a refinement, the fundamental is that only one object is looking after the creation of these AppConfig objects, only the factory knows if there are one or many.
And that leads me to another pet theory ... there is no such number as 1, when you start out it looks like a Singleton, then conmplexity grows, and you find a scenario where some part of your app (for example) uses one Config and another part uses a different one (Eg. in dynamic transition between versions). The factory can hide that complexity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With