Hi,
I'm making an MVC pattern based app and I though I would learn the principles first. I have reached a stage I need to connect the three elements. When Controller receives user action It calls right model. Now I need to register callback function so that when Model is done it will update view using that callback. Now I'm struggling in doing this and I need to make generic class that will handle all Model registration. Where do I begin to write such a class?
Sorry if something is unclear. Just point it out and I will make it clear.
Thanks!
Stefano Mtangoo 455 Senior Poster
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster
>> Now I need to register callback function so that when Model is done it will update view using that callback.
You have stumbled upon the reason why I don't like MVC very much. The "idea" of MVC is that the Model should be only a slave to the other components (I say "idea" because it's an old theoretical idea from a time where GUI was more theoretical than practical). Generally, people realize this by having the View run in a loop, always querying the state of the Model and updating anything that changes (or updating everything). Similarly, the Controller runs in a loop catching events of user input. While the Model just sits there, being a slave to the other two. For the Controller, it is totally appropriate. But for the View, it is just stupid and wasteful. So, yeah, you need callbacks initiated by the Model in order signify that some things have changed and need to be updated in the View. But how?
The idea of MVC is to separate the three things, but to what level? Conceptually or computationally. If you just want to conceptually separate the View from the Model, then you need to create an abstraction that wraps the notifications that the View wishes to respond to. Personally, I like to use the Visitor Pattern for this (and it is pretty much the only place I use it), in a manner that implements Inversion of Control. This way, on an abstract level, the control is in the hands of the View, but in practice, control is inverted. But this only achieves a conceptual separation (through the abstract visitor class / concept). If you need a computational isolation, then you need to have separate threads and asynchronous signals, but you can still implement that behind the visitor abstraction. Boost.Asio is a good candidate for doing that, but message-passing libraries are also an option.
To actually implement a visitor class to invert the control on the Model, just define the list of functions (or callbacks) that you need (maybe regrouped into different classes) and have the View provide the implementation for this (those) visitor(s) abstractions.
Of course, you can also register individual callbacks for each event, but it can get cluttered pretty quickly.
It depends on many factors, like the granularity of your events (anywhere from only having "something happened" events to having precise events like "item 2034 just changed by 23" or something), the responsiveness, the memory model, etc. etc.
Do tell what you have in mind, the kind of code you have put in place, and your constraints. That's gonna be a better start.
Stefano Mtangoo 455 Senior Poster
Starting from second paragraph, I'm watching Mike speaking in tongues ;)
Seriously now,I don't know Visitor pattern or invent control. Let me google.
May I ask, if you can help me with a conceptual example? I'm get stacked!
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster
>>May I ask, if you can help me with a conceptual example?
Ok, lets assume that you are building a numerical integrator for some dynamic system (an example I know very well). A classic (non-inverted) control flow for this problem would be to do this:
1) Setup the dynamic system and numerical integrator.
2) Set the initial state-vector.
3) Run the integrations:
3a) Perform one time-step of integration.
3b) Record the resulting state-vector after one step.
3c) Repeat until the end.
4) Record the end result of the integration.
The above is the normal control-flow, but this does not lend itself easily to the MVC pattern.
In MVC, the controller is used to setup the dynamic system and the integration parameters (time-step, tolerance, etc.). The model actually performs the numerical integration. The view is used to show the results, either as a graph or table, or file output, whatever.
You can see from the normal control flow that it requires the View to be in control of the integration (do one step, and record, and repeat). However, if you give a Visitor to the numerical integrator, you can invert that control flow to put the Model in control of the integration. So, you can define a visitor as so:
class IntegrationVisitor {
public:
virtual bool keepGoing() = 0;
virtual void initialize(double aInitTime, const std::vector<double>& aInitState) = 0;
virtual void recordState(double aTime, const std::vector<double>& aState) = 0;
virtual void finalize(double aFinalTime, const std::vector<double>& aFinalState) = 0;
virtual void signalFailure(const std::string& aFailureMessage) = 0;
};
And now your View part of the software provides a visitor that fulfills the above interface. The Model part takes the visitor object (by reference or pointer) and calls its functions when appropriate. This way, the Model is in control of the integration (but can be stopped by the visitor via the keepGoing() function), and that is inversion of control, very simple.
In MVC jargon, the visitor in this case is referred to as an "observer". This abstraction is the key point of separation between Model and View, because the View only has to implement the Visitor, and the Model only has to deal with the Visitor (abstractly). So, the Model and the View never interact directly with each other.
Computationally, however, they are still connected because calling the functions of the Visitor will cause the Model to stop executing its task for the time that the View takes to record / display / save / animate the results. So, to separate the execution, you have to use another thread(s) for the View and use some asynchronous messaging system to signal the "events" which come from the functions of the visitor being called.
Edited by mike_2000_17 because: n/a
Stefano Mtangoo 455 Senior Poster
thanks Mike,
my phone does not display codes well, but I will be on PC few hours to grasp the point.
Again thanks!
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.