Mvc – Decoupling UI code

couplingdesignmvcui

In my application I have several event handlers that perform some action in response to user interface events such as a button click or menu selection. The code in these event handlers looks like this for example:

void MyDialog::OnCommandLoadFile()
{
    char strFilter[] = { "Text Files (*.txt)|*.txt|All Files (*.*)|*.*||" };

    CFileDialog fileDlg(TRUE, ".txt", NULL, 0, strFilter);

    if( fileDlg.DoModal() == IDOK )
    {
        const std::string path = fileDlg.GetPathName();

        std::vector<std::string> urls;
        int maxNumberOfUrls = settings_->Get<int>(Settings::MaxNumberOfUrls);
        UrlProvider *urlProvider = new FileUrlProvider(path);
        urlProvider->GetUrls(urls, maxNumberOfUrls);

        webMonitoringService_->MonitorUrls(urls);

        DisplayMessage("URLs loaded.");
    }

}

This is typical of my event handlers. I don't code monolithic event handlers but they do "glue" various pieces together. I usually have some business-logic/service classes which the UI has a reference to and in the event handlers I make calls to one or more of these to perform the desired task.

What I'm wondering is is this still too coupled? If I wanted to turn this into a command line app I'd have to extract bits and pieces from the UI code. In the above example, there is a compound action going on so should I'm thinking it should look more like:

void MyDialog::OnCommandLoadFile()
{
    char strFilter[] = { "Text Files (*.txt)|*.txt|All Files (*.*)|*.*||" };

    CFileDialog fileDlg(TRUE, ".txt", NULL, 0, strFilter);

    if( fileDlg.DoModal() == IDOK )
    {
        const std::string path = fileDlg.GetPathName();

        application->MonitorUrlsFromFile(path);

        DisplayMessage("URLs loaded.");
    }

}

Is that right? In the above code what would "application" be? A controller? Is that the right abstraction for this? Whenever I need to perform some task in a UI handler, should it always be a one-liner (aside from getting data in or out of text boxes etc.) Anyone have a pointer to a tutorial that really covers this (in any programming language)?

Furthermore, if in fact you should abstract compound actions, how to you propagate error messages from within the compound abstraction back out to the UI? An exception hierarchy? Single exception with error code?

UPDATE

I'm looking at the Command Pattern which looks promising.

UPDATE 2

In the end I decided on refactoring my code as described in the Humble Dialog Box paper in the accepted answer. My understanding is that this is a Model View Presenter (MVP) type pattern and more specifically a Passive View. The refactoring is going smoothly. There are some rough edges in my understanding of the full application of the pattern when it comes to things like displaying message boxes and file open dialogs or dealing with event timers but overall I'm happier with my code; the tight coupling was bothering me.

I also found this "bundle": patterns & practices Web Client Developer Guidance: Model View Presenter (MVP) Bundle which has sample MVP code. It's a web project whereas my current implementation is desktop but I guess that's the beauty of MVP is that it partly doesn't matter. One thing I got from that was to dependency inject my service layer objects into the presenter rather than new'ing them inside my presenter class.

Best Answer

If you want to learn how to better decouple your GUI from your business logic, I suggest you read Michael Feathers` article "The humble dialog box"

If you got yourself familiar with that, and you want some more of that stuff, here is a Blog series "Build Your Own CAB" which explains all important variants of "MVC":

http://codebetter.com/jeremymiller/2007/07/26/the-build-your-own-cab-series-table-of-contents/

EDIT: according your example code: when you are going to use "MVP", that will mean not to have a "god object" application where you place MonitorUrlsFromFile, but a controller (or "presenter") class MyDialogController at first hand. Think of it when your program get 20 dialogs and all of them would place their handler logic in a class application - that will easily end up with a class having 5000 lines of code or more, which is definitely too big.

By MVP approach, you will only refactor MonitorUrlsFromFile to another more general place, when you need this function from more than one dialog and want to reuse it. Even then I would not make this an application class, better group functions for urls or url monitoring into one utility class.