Singletons are indeed usually globally available – that’s often what they’re for. But assuming ‘global is bad’ misses some good uses.
Singleton is indeed bad when it is a single global point for all components to find all global things. You can find then that the Singleton uses types or interfaces defined in component packages, and in turn these packages make use of the Singleton. So your packages, or components, depend on the Singleton which in turn depends on other packages… so all your components are interdependant through the singleton and you can’t decouple anything from anything else. This only Might Be Bad in your project, but is Always Bad in large software systems.
Singleton is also bad when used to bypass structured and/or object oriented programming; a Singleton might be used to hold data for a task instead of using a data-wrapping object and passing that as an argument. It might be used to shortcut data transfer around layers of a system. Again, this only Might Be Bad in a small prototype program, but is Always Bad in large software systems as they can make applications a nightmare to debug and update.
Banning Singletons altogether stops these abuses but also loses the benefits, which can be convenience, simple and obvious code, and easy maintenance.
Even the pico guys say that Logging is an exception, but exceptions are sneaky; they can either be one that ‘proves the rule’ because it really is exceptional, or one that demonstrates the rule is pants. In fact logging isn’t a special case; it is merely a centralised – and global – route for monitoring a particular kind of event.
Other messaging hubs – such as UI event queues – are similar. Configuration too benefits from a single class so that you can have one central place to configure your application. Pool factories necessarily require a Singleton (although Pooling is normally bad).
We want to centralise these tasks, but each one is a separate special to purpose Singleton; they are not combined into one single global Singleton. Which is how Singletons ought to be used. Note that in all these cases the Singleton implementation is ‘standalone’; our components depend on a particular specialised Singleton and its package, but the Singleton does not depend on our components or other ‘high level’ components.
This loose-coupling is best seen in message-passing hubs that tend to be Singletons (such as logging). The hub package must include whatever interfaces it requires for its message objects (or events), and these are implemented by whatever components use the hub package, either as senders or listeners
(Just trying out blog; this blog was cut and paste from web pages here)