Question
In the context of an MVC, desktop architecture, is there a canonical solution or a design pattern / best practice to give access to an immutable value class to multiple components at different levels of nesting?
Use case examples:
- User settings: Some controllers or views need to access the user settings so that their behavior complies to the user preferences
- Current theme: every view must have access to the current theme so that they know which colors, fonts, and styles to use
Note that these classes are not necessarily singletons (we could want to create different Theme
instances at a time for instance) BUT the current theme should only point to one instance at a time. This reference would be the single version of truth, even though the instance it references could change over time.
Concrete example
My MainWindow
component has far too many responsibilities so I want to break it down into just a few, higher level components.
These new components should have only one responsibility so that the MainWindow
is merely the glue which holds them together and delegates method calls when required.
But some of these sub-components need to access the user settings at some point. These settings are managed by SettingsComponent
which is a direct child of the MainWindow
. The only way other components can access the settings is to call methods from SettingsComponent
.
So, if I encapsulate the lower-level components into higher level components, they won’t have access to SettingsComponent anymore.
Some (bad?) solutions
1- Expose a static reference to the instance of MainWindow
(since there can be only one for the lifetime of the application).
To access the settings or the current theme, each component could then call: Gui.getMainWindowInstance().getSettingsComponent().getSettings()
2- Keep and manage a copy of the user settings inside every component which need to know about them. When the settings change, these components will be notified and update their own copy of the settings accordingly. This solution doesn't seem right because:
- There won't be a single version of truth anymore.
- It feels weird to have views keep a reference to an instance of the user settings
3- Externalize the Settings
from SettingsComponent
to a service or provider class. This class would expose static methods which could be consumed anywhere from any component. Pseudo-code example:
class SettingsProvider {
get(): Settings { /* ... */ }
update(settings: Settings): void { /* ... */ }
}
So from anywhere in my code I could do:
class SomeComponent {
someMethod(): void {
settings = SettingsProvider.get();
// do stuff
}
}
This third solution seems cleaner but I wonder if it would be a good practice or just makeup on a poorly designed software.
Am I missing an obvious, cleaner solution?
How is this problem usually solved? Is there any article, book, or online resource which provides a clean solution to this specific problem?