0

I am designating an architecture which uses some differents objects controller which implement an abstract_controller interface.

Their goal is to encapsulate the use of some data.

Some factories are responsible for creating and initializating the controllers.

Some controllers might need some other controllers, and every used controllers needs some information from the database, especially on first run.

Nb : In my application, clients must know about the catalogs they can order from.

For instance, if on an execution I need tu use the client_controller, client are created by the client_factory (and somehow provided), but in this case I must be able to provide information about catalogs as well, and initialize my catalog_controller (and so on).

So here, there would be only three dependencies :

  • client depends on the data in the database.
  • client depends on catalogs
  • catalog depends on data in the database. (assuming this is the only dependency of the catalog_controller)

What are options to indicate that xxx_controller requires yyy_controller or even zzz_knowledge ? In the first time I thought of maybe making corresponding requires_xxx_controller interface with a predicate, but then it seems I should make one interface for each and every controller, and then it wouldn't be really extendable.

My next idea was to make requirement and has_requirements interface , make controller, database_information (and some others types) implement requirement and controller has_requirements would return the list of dependecies it has, which I would store in an ordered set, ordered by insertion order, (which luckily exists in boost), but even then, I would be obligated to come up with a solution to return a collection of those requirements which I cannot build.

What flaws am i exposing to in theses cases ? Is there a commonly accepted solution for this problem ?

I doubt it changes anything big, but c++ is the language used in this application.

  • Can some classes use a Controller through the abstract interface, or must every class that uses a controller know the exact sub-type of controller being used? – Daniel T. Aug 6 '17 at 1:52
  • Yes, some classes will use the abstract controller. – Pierre-Antoine Guillaume Aug 6 '17 at 5:40
  • In what context are you using Controllers for things? Are you following a design pattern, e.g. MVC, MVVM, or MVP? – John Wu Aug 7 '17 at 19:23
  • @JohnWu I guess I am made a MVP, but I didn't know this pattern – Pierre-Antoine Guillaume Aug 8 '17 at 6:47
0

I feel like the answers you have gotten so far don't actually address the question you had...

You have a number of controllers that all derive from an abstract_controller interface and that's good so other code can deal with a controller without having to know its type. However, the controller factory has to know about specific types of controllers and how to construct them. There's no getting around that.

In your example, you mention that a client controller needs "many" (0..n) catalog controllers. I suggest you create some sort of specification language (this could be JSON, XML, a simple CSV, or a special C++ "specification" class) that tells the factory which controllers to build and how to hook them up. The ControllerFactory is handed a specification, parses it, creates and configures the necessary sub-controllers and then produces the needed controller.

To make the ControllerFactory extensible, you can define some more interfaces, one for each type of sub-controller factory. For your example, you would need a separate ClientControllerFactory and CatalogControllerFactory. In this, more extensible idea, each factory subtype would know how to parse a particular piece of a specification.

When the ClientControllerFactory is handed a specification object, it would create the client parts and then delegate the catalog component part of the specification to the CatalogControllerFactory which would then make the catalogs and pass them back to the client factory for insertion into the client.

If you want to make this even more extensible, you could define a separate factory class for each controller class. Then you would have a MasterFactory that is handed an array of ControllerFactories. When the master gets the specification, it would hand the spec to each contained factory which would look for the parts of the spec it can build and return them. The master would then assemble the controller objects according to the spec. This way, adding a new controller sub-type would be a simple matter of defining the controller class and its factory (that would know how to read the spec to find out if its particular controller is needed) and insert an instance of the new factory into the master factory.

  • In the end, the client controller will manage all the clients, and the catalog controller will manage all the catalogs. But the client controller will know of the catalog controller and each client will know of the catalogs (or at least a way to identify them) it can order from – Pierre-Antoine Guillaume Aug 6 '17 at 23:00
  • So what you suggest is to give a list of which abstract-specific controllers must be built as a string. It sounds practical, but at the same time quite easy to misuse, doesn't it ? I will think this over and come back haha – Pierre-Antoine Guillaume Aug 6 '17 at 23:04
  • 1
    Why would it be an improvement to write XML/JSON/CSV to hook up your objects rather than just writing the C++? – Winston Ewert Aug 7 '17 at 15:18
  • The specification need not be in a language other than C++. I updated the answer. The idea here though is to create a DSL for configuration, something that can be changed by a non-programmer, possibly without recompiling. As long as the specification is separate from the factory it can be in C++. The target is satisfaction of the Open/Closed Principle. Make the factory configurable without having to dig in and edit the code in the factory, but instead by adding objects to it. – Daniel T. Aug 7 '17 at 15:38
7

Whenever a piece of code needs something, it should take a parameter. Don't do anything more complicated than that.

If you want to create an object that needs a dependency use constructor parameters.

class client_controller {
     client_controller(database_information*, catalog_controller*);
}

If you just need a function, use method parameters:

void do_foo(database_information*, catalog_controller*);

Then, when you construct that object or call those functions, pass the parameters.

The only thing you'll accomplish by going down the path of building a complex framework around passing dependencies of things is bloating your code and making it difficult for yourself and others to understand your code.

  • Well one way or another you're going to end up passing dependencies around. It's just a lot nicer if the things that need the dependencies don't have to know how to find them. It's better to just accept them being passed in. The work of passing them around still has to be done somewhere. But now it's not mixed with the code that uses the dependencies in a confusing blob. – candied_orange Aug 6 '17 at 15:28
  • @CandiedOrange, well, it depends on how you do it. I find that most attempts to seperate the passing in from the working end up creating an even more confusing blob. – Winston Ewert Aug 7 '17 at 15:17
1

According to your specific client/catalog example, I would follow a different approach.

Because you've said that both client and catalog depend on data from database, I would create a client_repository and a catalog_repository, which are only responsible for handling database operations.

Then, I would create a ClientCatalogController (or ClientCatalogManager), which is responsible for retrieving clients, along with their respective catalogs, and handle other logic that the application requires regarding these two entities.

In other words, I wouldn't use the factories you mentioned, because the data comes from DB, and I would place all logic that my application needs in one manager (or controller) class.

If you need something more generic despite the specific example you gave, I would take a look into how a framework like MEF works. Basically, it searches during runtime for interfaces that implement what you're expecting.

https://docs.microsoft.com/en-us/dotnet/framework/mef/

  • I now have much more experience than when I asked that question, and your answer really looks like what I design at the moment (for something completely different, actually), but on the contrary, I really do use the factories I mentionned previously. For instance, the application (a website) is ran by different companies which have differents constraint (eg. logistical requirements...) and these factories produce object coupled with visitors that really makes the system flexible. The global flow of my design is pretty much like that, and I haven't faced deep issues with that yet. – Pierre-Antoine Guillaume Feb 2 '18 at 8:41
  • Hence my question, what do you mean 'I wouldn't use the factories you mentioned, because the data comes from DB' ? I want to be clear, my factory is specific to my database (or I should say is specific to the fact that comes from a relation with field names), but it is not responsible for the actual 'fetching'. – Pierre-Antoine Guillaume Feb 2 '18 at 8:43
  • @PierreAntoineGuillaume - now it makes sense the usage of the factories; I thought you were using factories like repositories for DB data only. – Emerson Cardoso Feb 5 '18 at 10:52
-1

This assertion is incorrect: "clients must know about the catalogs they can order from". Presumably this means "Some function in the Client class must call a function in the Catalog class." But your customer doesn't care about that. Whether or not you have a "Client" class, and whether or not it depends on a "Catalog" class is an implementation decision, not a business rule.

You can always assign functions to classes in such a way that classes are not circularly dependent. Or you can break unwanted direct dependencies by introducing abstract classes (e.g. the "Observer" pattern).

  • Why are you bringing up what the customer cares about? – Winston Ewert Aug 6 '17 at 2:03
  • Because since the customer doesn't we don't have to create madding circular dependencies? – candied_orange Aug 6 '17 at 3:52
  • It means "given a client, what is the list of catalog can he order from ?" – Pierre-Antoine Guillaume Aug 6 '17 at 5:45
  • The classes I use are meant to represent some parts of the reality. And by reality, I mean specifications. So if the specification tells me "a client can only order from an explicitely defined subset of catalogs", it makes sense to me to make client know about the catalog he can order from. That way, I can tick the line in the spec. How could that buisness decision not be tied to the implementation ? Or maybe a better question, what else do you suggest ? – Pierre-Antoine Guillaume Aug 6 '17 at 6:38
  • 1
    If you read the example in the question carefully, you will see that the OP means "A depends on B and B depends on C" with the term "recursive dependency". That is also how I understand the term "recursive" in such a context. – Bart van Ingen Schenau Aug 9 '17 at 17:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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