mercredi 14 novembre 2018

What are the pros and cons of keeping most of an application's state in a single struct?

In my application, I have a few classes. Many of these classes share common state like a reference to the logger for example. For example, both A and B require some common state to get their job done.

class A {
  Logger &logger;
  CommonThing &thing;

public:
  void performTaskA();
};

class B {
  Logger &logger;
  CommonThing &thing;
  std::vector<OtherThing> stuff;

public:
  void performTaskB();
};

Another example of a pattern from my application: C holds an instance of A because C needs to performTaskA in order to performTaskC.

class C {
  Logger &logger;
  CommonThing &thing;
  A a;

public:
  void performTaskC() {
    a.performTaskA();
  }
};

C is basically storing Logger and CommonThing twice. A doesn't actually have any state of its own so C could very well construct A in-place every time it needs to access it's interface.

I'm a fan of dependency injection. If an object is required to perform an operation, I pass it in. However, this has resulted in functions and constructors taking many parameters. I frequently have to wrap parameter lists down multiple lines because they're so damn long.

The operations being performed require a lot of state. That is the nature of the operations. If I could, functions would just have less dependencies but that is not really an option. I have an idea for solving some of the mentioned problems.

I stumbled apon a code snippet from a C++ compiler. I don't remember the details but I saw a number of functions, each taking a pointer to a context object as a parameter. I could put all of the common state into a single struct and then pass around a reference to the struct.

struct Context {
  Logger logger;
  CommonThing thing;
};

void performTaskA(Context &);
void performTaskC(Context &);

Neither A nor C need to be classes anymore. They can just be groups of functions that take a context. The reason they were classes before is because if they were functions, they would have very long parameter lists.

The use of a context struct seems to solve most of the problems but it brings along its own set of problems. What I'm essentially making is a "god class" except that the member functions are grouped together into multiple files. It's nolonger obvious what a function accesses because it could access anything. Although, if a function suddenly needs to access something, I nolonger need to update the parameter lists of a bunch of functions.

Is the context struct better than what I have now?

I really hope this isn't off-topic. I've tried to keep it generic so that answers could help more than one person. I wanted to ask here before I make a major change to the my codebase and rewirte a whole lot of stuff.

Aucun commentaire:

Enregistrer un commentaire