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 codebase and rewrite a whole lot of stuff.

  • for the objects that have huge constructors due to all their dependencies, is it possible for you to break them down and SRP them up a bit? Lots of dependencies is usually a sign that a class is doing too much – GoatInTheMachine Nov 15 at 12:10
  • @GoatInTheMachine I think I need to look at the code and rethink the design. Any advice I get here will be too generic. Getting useful advice would involve posting my whole code base and asking someone else to refactor it for me. – Kerndog73 Nov 15 at 12:15
up vote 3 down vote accepted

I think you already sum up the pros and cons.

Pros : reduce large number of parameters

Cons : 'god object' increases coupling and gets bigger easily but hard to make smaller.

I would say that the Cons out weigh the Pros. There other ways to control the number of required injected parameters. Besides a DI container should auto populate them for you, reducing the problem.somewhat.

Also the two methods are not entirely functionally equivilant. You can pass in different loggers per class for example.

Furthermore, the problem of having these deep object trees is more than just long lists of construction parameters.

It's possibly a bit of a code smell, and maybe indicates that the code could be refactored to a shallower object graph. Perhaps, given that you say these functions have no state of their own, a more Anemic Object pattern where a handler with methods processes a whole list of A's which only contain data would iron out your dependencies to a single layer?

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.