Model-View-Controller is a programming design pattern which was created
to solve the design problem of a rather frequent application: Displaying data
to the user (and possibly handling input from the user).
The basic idea of
this pattern is to divide the program (or module) into three main modules: The Model, the View and theController. In its purest form, the MVC pattern works like this:
1. The Model is, simply put, the module which handles the data
of the program. It could be, for example, a module which interacts with a
database. In its simplest form it could simply be some kind of data container
(such as a list), depending on the application.
The Model module has no functionality
on its own other than as an interface between the data and the rest of the
program. It handles the data only to the extent that is needed for it to be
stored and restored but otherwise doesn't make any decisions about what to do
with the data.
2. The View is the module whose task is to display data to the
user. It does not have any functionality in itself, other than what is needed
to transform and lay out the data as needed by the display format. In other
words, the View acts as an interface between the display (which can be a
physical display or eg. a document format) and the rest of the program, and
doesn't have any functionality related to anything else than displaying the
data.
3. The Controller is the core module which makes all the
decisions. It has all the relevant functionality of the program and interacts
with the Model and the View, commanding them and passing data between them as
needed.
There are two schools
of thought with regard to whether the View interacts directly with the Model or
not. In one school of thought the View and the Model are completely separate
and have no connection whatsoever. All the data between the two is handled by
the Controller. In the other school of thought the Controller can command the
View to retrieve data from the Model so that the data doesn't have to be
transferred by the Controller. (This naturally creates a dependency between the
View and the Model.) In other words, the functionality of the View is enhanced
as much as is needed for it to interact with the Model in order to retrieve
data (but otherwise the View has no functionality of its own.)
Case example
A perfect example of where the MVC pattern is useful is a web server:
1. The Model is the
module which interacts with the database (in the simplest designs this could be
directly the library which is used to query the database using eg. SQL).
2. The View is the
module which generates HTML from the data.
3. The Controller
contains all the other functionality of the server (eg. it decides which page
to display, generates dynamic content, handles session and cookie data, etc.)
One would hastily think: "Don't all web servers actually
do exactly this (at least those which produce dynamic content)? Isn't this
pattern rather ubiquitous?"
The answer is no: The critical element which distinguishes the MVC
pattern from a non-MVC design is the separation between the View and the
Controller. They must be completely separate and independent modules. If the
Controller outputs HTML directly (which is extremely usual), then it breaks the
MVC pattern because now there is no abstraction between the functionality of
the Controller and the output that the program produces.
Or put in other words: The Controller must not know that the output is
HTML. It must be completely agnostic to what format is being used as output. If
it outputs HTML directly, this abstraction is broken and it's not the MVC
pattern anylonger.
(The level of abstraction required between the Controller and the Model
is debatable. One could argue that SQL is enough of an abstraction, as it
doesn't fix the exact format of the database. Others might argue that SQL is
not enough, as different database libraries use slightly different versions of
SQL, and thus the exact query language should be hidden inside the Model
module.)
One could just as well rename this special case as the "DDC"
(Database-Document-Controller) pattern.
Motivation
Why go through the trouble of designing your program like this? This
design pattern was not devised just for the sake of it. There are good ideas
behind it (at least in theory).
The complete abstraction between the Controller and the View means, as
mentioned earlier, that the Controller is completely unaware of the actual
output format being used. This means that if we want to change the output
format to something else, it becomes enormously easier: It's enough to create a
new View for the new output format and make the Controller use that instead
(the switch can even be done during the execution of the program if needed).
For example, suppose that besides the server returning the data in HTML
format you would also want support for it to return the data in PDF format. It
becomes as easy as writing a new View with the same interface as the old one,
but which outputs the data in PDF format and make the Controller use that. (The
layout of the PDF might need to be slightly different from the HTML, but this
is what the View module is for.)
As you might imagine, in an optimal case, with a perfect design, this
saves an enormous amount of work. If, however, the Controller had printed HTML
directly, making this modification would have required a lot more work, if not
even a complete redesign.
So now it becomes very easy to add all kinds of different output
formats. For example, you might want to be able to output the data in plain
text, or even as a Java or Flash application. Moreover, you could even be able
to relatively easily port the application to a completely different environment
and make it eg. a Windows application (in which case the View would then be a wrapper
around the Windows API, QT or whatever).
Likewise the abstraction between the Controller and the Model means that
the format in which the data is stored can be easily changed without having to
modify the Controller or the View. If, for example, the Controller is directly
reading and writing raw data to files, changing it to eg. use a database
instead would be a lot more laborious than if an abstract Model had been used
instead.
(And this also means that the same program could support many different
data storage systems in the same way as it could support different View
formats.)
The practice
So all that sounds really nice and fancy, but does it work in practice?
In web servers it might work like a charm. However, the MVC pattern is
also being used in many other environments, not all of them being strictly an
application for displaying and updating data in a database.
One prominent environment where the MVC pattern is being heavily
promoted is the MacOS X and iPhone development environment. Apple uses and
recommends using the MVC pattern in all programs created for those platforms.
The Cocoa and Cocoa Touch libraries are designed around this pattern.
So, does the MVC pattern work for a graphical application like an iPhone
program?
Regardless of what Apple claims, my answer is no. At least not in its
purest form. Programs might follow something slightly resembling MVC, but in
practice they will end up mixing especially the View and the Controller
functionalities because trying to strictly enforce their separation is actually
counterproductive. The end result is a program which does not really have the
benefits of this separation (ie. those described earlier).
But that isn't necessarily a bad thing. It would be nice in theory if the Controller was so abstract that
it could be used as-is in a completely different environment by only changing
the View, but in practice this is basically never a necessity. You don't
usually write an iPhone program which could output its data to the screen or to
a HTML file. It just doesn't work like that. (If you really needed to generate
HTML from some data, you would simply write a separate module for that purpose,
which has nothing to do with your Views.)
As said, the major problem with trying to enforce a strict MVC design in
an iPhone (and in general in any graphical) program is that it's very
counter-productive.
The problem is that if you have a very complex view with a lot of
elements and lot of functionality (which is typically the case with the main
view of a program, eg. a game), if all the functionality is in the Controller
(as demanded by strict MVC), your Controller class will start growing out of
control and become extremely complex. This, rather ironically, produces a
result which is against good object-oriented design principles: The Controller
is tasked with way too much. Many of these tasks are things which would better
be done by the "View" or the "Model" (so to speak) themselves
in a good OO design.
Even if you try to split all the functionality inside the Controller
into smaller modules in order to keep the module sizes manageable (and while
still trying to impose a strict MVC pattern), you will often end up with
needless complexity because now there will be a huge amount of interaction and
dependencies between these modules and the View. This might even end up as a
broken MVC design where you have several "subcontrollers"
all interacting with the View and between themselves.
The fact is that it is often the case that if you move certain
functionality from the Controller to the "View", the end result will
be simpler, more intuitive and a consirably better OO design. Now the
"View" will have a much more active role, will have more
functionality of its own (functionality which should be in the Controller in a
strict MVC design), but the Controller will now be more manageable and more
focused on its own role, rather than trying to manage a million different
things, most of which don't really concern it.
In other words, the level of abstraction will now be better, with a
simpler class design. Rather than have the Controller take care of everything,
the tasks will now be better distributed: Tasks related to the view are now in
the "View" class, away from the Controller class. The Controller
class can now focus on its own core functionalities.
The same goes, of course, with the "Model" module. Data
handling routines can be moved from the Controller to the "Model",
giving it a more active role, but at the same time making the Controller
simpler and more focused.
Also the "View" can often interact directly with the
"Model", completely bypassing the Controller (with tasks which
should, once again, be in the Controller in a strict MVC design.)
Of course this is not the MVC pattern
anymore (except perhaps in a very loose sense.) The theoretical benefits of
that design pattern have been destroyed by doing this, so there's little
benefit.
However, the fact remains that in an iPhone application there's
extremely seldom any need for the abstraction offered by the MVC, and strictly
adhering to it is, on the contrary, very counter-productive. Your Controller
classes tend to become very large and complicated, ridden with with tons of
functionality which doesn't really concern them,
functionality which would be better delegated to the "View" and the
"Model" themselves for a much cleaner object-oriented design.
Another problem is that a strict MVC design would require for each View
to have its own Controller (although the Model can be shared among several
controllers even in a pure MVC design, for practical reasons).
In practice, however, if you adhere to this in an application with
dozens of (often similar) views, your class design will also become needlessly
complex. In practice a simpler design is to have one Controller handling
several (somehow related) views. For example, if you have a Controller which
manages help screens, and there are many of such screens (eg. one help screen
for each major feature in the program), it's much simpler to have one single
Controller which manages all these help views rather than have one Controller
for each. Such a Controller doesn't usually need to be very complicated even if
it has to handle a half dozen of such views, and thus it makes no sense to
create one Controller class for each view.
Thus in practice you end up having a kind of
"Model - Multiple Views - Controller" design
by necessity. (Although some would argue that this is an acceptable MVC design
as it doesn't really break the MVC abstraction model.)
When programming for the iPhone you will probably end up with classes
with the word "Controller" and "View" in them, but those
will often be misnomers (except maybe with the simplest MVC triplets.)
The same is probably true for other GUI environments.
0 comments:
Post a Comment