Question

The litmus test for me for a good MVC implementation is how easy it is to swap out the view. I've always done this really badly due to being lazy but now I want to do it right. This is in C++ but it should apply equally to non-desktop applications, if I am to believe the hype.

Here is one example: the application controller has to check some URL for existence in the background. It may connect to the "URL available" event (using Boost Signals) as follows:

BackgroundUrlCheckerThread(Controller & controller)
{
   // ...
   signalUrlAvailable.connect(
      boost::bind(&Controller::urlAvailable,&controller,_1))
}

So what does Controller::urlAvailable look like?

Here is one possibility:

void
Controller::urlAvailable(Url url)
{
    if(!view->askUser("URL available, wanna download it?"))
      return;
    else
      // Download the url in a new thread, repeat
}

This, to me, seems like a gross coupling of the view and the controller. Such a coupling makes it impossible to implement the view when using the web (coroutines aside.)

Another possibility:

void
Controller::urlAvailable(Url url)
{
   urlAvailableSignal(url); // Now, any view interested can do what it wants
}

I'm partial to the latter but it appears that if I do this there will be:

  1. 40 billion such signals. The application controller can get huge for a non-trivial application
  2. A very real possibility that a given view accidentally ignores some signals (APIs can inform you at link-time, but signals/slots are run-time)

So what do you suggest to remove coupling and also keep complexity down? Thanks in advance.

Was it helpful?

Solution

The litmus test for me for a good MVC implementation is how easy it is to swap out the view.

I'll probably draw fire for saying this, but I don't agree with this statement. This looks good on paper, but real-world examples show that a good UI is responsive and interactive, which often times necessitates intertwining the view and controller. Trying to code a completely generic controller to handle unforeseen theoretical views adds a ton of code and complexity to both the controller(s) and the views. Interlinked views/controller worked better in my experience - I think of it as "M(VC)".

I would say litmus test for a good MVC implementation is how easily you can "add" another view/controller pair to a model. Are the changes to the model from one view/controller (e.g. desktop operator) propagated out to the other view/controller (e.g. web remote user). Is the model generic enough to support different view/controller paradigms (e.g. desktop GUI, command-line, scheduled/batched input, web-based UI, web service, etc.)?

This isn't to say that controller code can't be shared (e.g. derive from a common base), but you do have to find the right line between what should be handled by the controller (external manipulation of the model) and what should be considered part of the behavior of the model (internal transitions of the model). Ditto for view code.

I think reading some of the answers under "What goes into the “Controller” in “MVC” would also help with this.

OTHER TIPS

You keep them decoupling using the 'm' - Model and use (in concept) command-liked pattern and listener pattern to keep the complexity down.

So your controller may looks like this:

void
Controller::urlAvailable(Url url)
{
   Controller::fireSignal("urlAvailable", url, ... other possible parameter);
}
Controller::fireSignal(char* cmd, Url url, ... other possible parameters) {
   Model &M   = new Model();
   M->command = cmd;
   M->url     = url;
   M-> ... other possible
   for(int v = Controller::ViewCount; --v >= 0; )
      Controller::Views[v]->notice(M);
}

NOTE: I am not C++ programmer so forgive me for wrong grammar.

The whole idea of MVC is to use M(odel) to decoupling C(ontrol) from V(iew). The example is an extremely simplified. The more practical one is to use different model for different kind of similar signal.

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top