What is the best way to share a configuration object between classes?

Let's say that I have classes M, A, B, C. M is the main class of my application (that is, the one that performs most of the job) and has this structure

class M { public: // Something here. private: Conifg config; A a; std::vector<B> bs; const C* c; }; 

Basically I create an instance m of class M, and I want to install my configuration object, say by reading it from a file. The configuration object is not something special, it can be a protocol buffer or a simple structure.

Now I want a, b and c to be able to access the configuration object, because there are some global settings that they need. These settings are global, they do not change and are the same for each instance of A, B and C (and M). What I am doing now has a static field in each class A, B, and C, and I set up a copy of the configuration object for each instance of these classes. I do not want these classes to know about M. Is this the best solution? Should I think of a global configuration variable?

+6
source share
4 answers

I would advise you to use an additional static class for configuration instead of static fields in all classes where you include the header in the places you need.

Implement a static constructor in which you initialize all the data that you want to use in static members. I think that would be the best solution.

+4
source

Just pass the Config object to constructors A, B, and C (in particular, pass a reference to the Config object, which is stored in M.

This gives you:

  • (you can easily change the configuration object for testing purposes
  • ease of reuse (you do not have β€œinvisible” dependencies on global variables that should be there. All the needs of A, B and C for existence are what they are indicated in their constructors.
  • flexibility (you can create different configuration objects to go to different classes if you need)
  • because the person reading your code should not be surprised: "Where does the configuration object come from? Who else could change it? Can I be sure that it was initialized at this stage?". Classes A, B, and C are self-contained and can be read and understood in isolation.

But whatever you do, do not use singleton and try to avoid static / global data in general.

+8
source

I personally would prefer to somehow pass this ABC configuration object over than using global / static objects. How to skip it (refer) as an argument when building bc or set it later through a call to set_config ()?

+4
source

I found the most suitable solutions for problems such as using a static function. If you use any object interface, hide it behind these functions.

Here is an example.

 namespace config { // public interface that is used a lot bool GetConfigValue(const std::string &key, std::string &val); } namespace config { namespace detail { // detail interface that is used for setup and tear down class Config { public: virtual ~Config() {} virtual bool get(const std::string &key, std::string &val) = 0; }; void RegisterConfig(Config *cfg); void ResetConfig(); }} 

Honestly, you will eventually have to change the interface and it will suck. The more you find the code, the higher the risk. So keep it simple.

As a background, this is a cross-cutting issue that is usually annoying. You really do not want to transfer such things to your objects. Aspect-oriented programming research can be interesting as they talk a lot about the subject.

+3
source

Source: https://habr.com/ru/post/892513/


All Articles