OOP design. Tree of classes containing classes containing classes...

Posted on 2014-03-29
Medium Priority
Last Modified: 2014-04-07
I'm tinkering with developing a Model-View-Controller design of classes. I've ended up with something like this:
        v                      v
      Model                Controller
        |                      |
   +----+-----+           +----+--------+
   |          |           |             |
   v          v           v             v
 ModelA    ModelB    ControllerX   ControllerY
 data1      data2

Open in new window

Now suppose ControllerY wants to fetch data1 and data2. I could pass Machine down to ControllerY, then ControllerY could call

Open in new window

to fetch the data. However, now I have a fragile design, where I can't make any changes to the overall structure of the Model, because Controller relies on that structure being there.

So I thought, "Maybe Controller should just pass data1 to ControllerY, since that's what it really needs. ControllerY doesn't really need the entire Machine class, it just needs data1. That should make it easier to test, as I don't have to instantiate an entire Machine class (which ironically contains ControllerY) and pass it to ControllerY in order to test it."

However, I came up with a problem in how to do this.

When I instantiate my Machine class, a whole cascade of class creation happens, because Machine has a Model class and a Controller class, which it instantiates; the Model class has a ModelA class and a ModelB class, which it instantiates; then the Controller class has a ControllerX and ControllerY class, which it instantiates.

And I'm supposed to initialize all this in the constructors, using constructor initialization lists. I don't see how in the Controller constructor initialization list, to extract and pass data1 to ControllerY constructor.

I could probably figure out how to move the extraction of data1 from Machine up to Controller, maybe something like this:
Machine& machine;
Data1 data1;
Controller::Controller(Machine& m) : machine(m), data1(machine.Controller.data1)

Open in new window

(The syntax probably isn't quite correct, but the general idea is to extract it in the initialization list. Then I can pass it on to ControllerX when it gets instantiated.)

I've discovered constructor initialization lists are difficult to debug. There's nowhere to set a breakpoint. It all happens at once. And a whole cascade of classes being constructed all at once using initialization lists quickly becomes a big problem to debug. Especially if I anticipate making any changes in the future, I foresee endless frustration debugging the creation of these classes.

I'm trying to avoid using new to create classes, because this isn't managed code.

So how do I avoid this problem at the design stage? What trick or design pattern am I missing?
Question by:deleyd
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
LVL 35

Assisted Solution

sarabande earned 2000 total points
ID: 39966417
probably you should reconsider the hierarchy tree.

I would do

machine is parent of controllers. controller is parent of models. model is parent of views.

each level may have a baseclass  (for example model baseclass) where you could have data and functions common to all derived classes of that level.

each parent class holds a container with baseclass pointers of its child level. so you easily can get all models to a container and can go further by means of virtual calls.

I'm trying to avoid using new to create classes, because this isn't managed code.
the 'new' in managed code and 'new' in (unmanaged) c++ have little in common. while in c++ you would create a pointer pointing to allocated heap space (and have to care for freeing the dynamic space after use and not use the pointer after freeing)  the managed c++ would do all this management for you. storing baseclass pointers in a container is the only way to have a dynamic list of child objects which may be different derived classes.

to encapsulate the 'new' on these objects you may think of using the factory pattern to create child objects by name rather than by class.


Author Comment

ID: 39967944
Is that the same as Model-View-Presenter?

Author Comment

ID: 39968000
As I play with my class diagram, moving to Machine -> Controller -> Model -> View,

well now I have Model controlling the View with no Controller in between.

It also hearkens back to an older question I had, which was, if I'm displaying a Menu, does the data for the Menu go in the Model?

The Menu is dependent on the screen size, and Model isn't supposed to know about the View, so Menu text doesn't go in the Model.

Likewise, Menu text doesn't go in the View, because then I have a thick View.

It was suggested to me that Menu text actually should go in the Controller.

(Are there any examples of an actual C++ OOP MVC design? (Or MVP, or anything good?))
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

LVL 35

Assisted Solution

sarabande earned 2000 total points
ID: 39969020
Is that the same as Model-View-Presenter?

no, as far as I know, the presenter is responsible to show data in a suitable way for a specific output device, for example for monitor, notebook, smartphone.

well now I have Model controlling the View with no Controller in between.
it depends on the tasks for the controller if that is right. you also could make the controller manage both models and views. I also know architectures where the controller(s) only manage(s) all views and has no relation to the model. if you have a controller that was responsible to synchronize models, it would be parent of models.

displaying a Menu, does the data for the Menu go in the Model?
normally menu texts are coming from resources which were loaded in the presentation layer, what is the view. resources give a means to support difference languages. if your controller is an ui controller it could have an own frame and menus which are independent on the views. then, the controller would provide the texts (or load from resources). the model would not care for menus beside of menus which contain data, for example the recent files list.


Author Comment

ID: 39972418
I just read some articles on the "DCI" Data Context Interaction design pattern. Didn't fully understand the proposed solution of "injecting" code into classes.

I do see the problem is somewhere needs to go the code that handles interaction between two classes. I thought that's what the Controller was for.

Have you heard of this DCI idea?
LVL 35

Accepted Solution

sarabande earned 2000 total points
ID: 39973116
Have you heard of this DCI idea?
no, not as a design pattern. I read an article about it, though.

but the idea of designing roles and interactions as classes, is a often used design. the problem with such "abstract" objects often is that differently to real objects (for example model, view) it is difficult to have a common agreement on them.

I thought that's what the Controller was for. 

Open in new window

no, for your task an ui controller would be responsible for displaying both the caller view and the target view at one screen. it also might be responsible to pass user input to the current active view.

an interaction object would be if you move data from model1 to model2 using the view1 and show the results both in view1 and view2. you could implement this as a function of the controller, using functions of the views and models. in the dci you would have a interaction object which lives only for the one transaction and would do the job. I know the design for server-client interactions, where it is a valid design pattern.


Author Closing Comment

ID: 39984284
I guess there's no "correct" way of doing it. I like the idea of reorganizing the hierarchy of classes.

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses
Course of the Month13 days, 22 hours left to enroll

801 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question