This is a quasi-philosophical article on an aspect of good OOP.
It seems that object oriented programming is more like governing a society (formed by your objects) by defining the local responsibilities of the objects and then “letting them act”. From which comes emergence, the behavior of a complex system. The best exmples are those where “available” objects (society members) are collected at runtime, to register actions, menu contributions and the like.
Many people, however, have the same misunderstanding that many western governments have about the best policies in their society. Governments think that a state will run best if more or less everything is under the central (hierarchical) control of the state. This is an analogy for procedural programming, a paradigm that many people still cling to when using classes and objects.
Now also an OOP program is executed in strict hierarchical manner, starting from
main(). But it is still possible to create an abstraction level (using some basic libraries) that provide this environment where objects can thought to be “free” members of the object society, responsible for nothing more than interacting with their neighbor objects that they “find”, and without (or nearly without) any central governance. For example, library functions as they are implemented in Eclipse RCP provide parts of this: finding the program’s plugins in the workspace, resolving their dependencies, collecting menu items at runtime etc.. The more of a program’s behavior is defined at runtime by the local object interactions that “just happen”, the better the OOP programming style. The advantage of this style is compact and understandable and flexible code. It is compact as most behavior is offloaded to structure, namely to the data structures of connected objects, which will emerge at runtime from objects “finding each other”.
Singleton patterns are nearly always a hint to bad OOP style, to still using the procedural programming paradigm. The exception is where singletons are employed to create the abstraction level where free objects and local objects interaction is possible. This level, comparable to a part of the set of natural laws in the physical world, may need central object registries etc. that need the singleton design pattern.
If one has multiple semantic hierarchy levels in a program (which is usually the case), governance as pointed out here should be used only within one level, while hierarchical programming is used to arbitrate between the levels. Several (ideally probably: all) objects on one level will get governed (in the style pointed out here) by one object on the level above.