Blog-Archiv

Sonntag, 5. Februar 2017

The Model-View-Controller Concept

MVC is one of the most beloved acronyms in software teams. It stands for Model-View-Controller, originally published as a Smalltalk programming concept.

MVC is a very personal thing. When you talk with people, you'll find all kinds of perceptions:

a controller is view-bound,
a controller is model-bound,
a model is view-bound,
all three depend on each other,
only the model is reusable,
model and controller are reusable, but not the view,
....

Due to these different understandings, its history was quite eventful. First MVC was said not to be a design pattern, only a paradigm. If you search the Internet today, you'll find a lot for "MVC pattern", also Wikipedia calls it so. Besides, you will find lots of related terms like MVP, MVVM, MVW, ...

Whatever MVC was, is, and will be, I would like to record my personal understanding of MVC in this Blog.

Where MVC is used

MVC is in the presentation-layer, which sits on the business-layer, which again sits on the persistence-layer. These three tiers are independent of the fact whether an application is a web- or a desktop-application.

In this diagram, the term MVP (Model-View-Presenter) was used instead of MVC. There is a slight difference between them, but essentially they both serve the same purpose. (My next Blog will be about MVP.)

The higher you get in this layered model, the more programming efforts you will find. The presentation-layer is the most expensive one. Thus it is worth investigating about good concepts there. MVC is one. It makes maintenance easier by clearly separating responsibilities. And maintaining software is much more expensive than writing software!

What MVC is

The view notifies the controller about user inputs. The controller then performs the according model changes. The model changes are published to any model listener, and the view is one. A model could have several views attached, which all would receive the changes done by the controller.

Model 1 : n View A model can be connected to several views at the same time, but a view can render just one model at a time.
View 1 : 1
or
1 : n
Controller A view normally is connected to just one controller, and a controller can serve just one view at a time; although MDI controllers hold several views, just one of these views is in foreground and sends events.
Considering the 1:1 cardinality, we could regard a controller to be a view wrapper, that's the way how it was done in Swing PLAF (exchangeable look & feel, "skin").
But it may also make sense to connect different parts of a view to several controller instances of different types.
Controller n : 1
or
1 : 1
Model A controller can be connected to just one model at a time, and, as a model can be connected to several views, a model also can be connected to several controllers at the same time.
When a controller is connected to several views, it should be connected to just one model.
Controllers are made to switch between model instances of the same type, that means, another model can be loaded into the same view and controller.

The view is not allowed to access the model, e.g. to retrieve some property value. The view is also not allowed to access the controller, except by firing user input events. The model is not allowed to access the view, except by firing user model change events. All presentation logic should be implemented in the controller, which is allowed to access both view and model.


Model

Responsibilities:
  1. let read data programmatically,
  2. let write data programmatically,
  3. provide listening to changes.

What could be inside a model:

  • exactly one piece of data, e.g. an Integer or a String,
  • a collection of such data, all of same type and semantic,
  • an object, consisting of several pieces of data with different semantics (properties),
  • an aggregation of such objects, as
    • collection or
    • tree,
  • one or more other models

Due to the fact that a model can contain a collection of objects (of the same type), I find the term Model-Item very useful. That could be an implementation-unit supporting view capabilities like list, table and tree.

Although we will mostly be editing objects and lists and trees of them, we should not forget about the very complex rich-text document model, providing a DOM (like used for web browsers) together with its sometimes cross-cutting rendering styles (CSS).

View

Responsibilities:
  1. let the user read data visually,
  2. let the user write data manually,
  3. let manipulate data visibility programmatically (e.g. enable and disable fields),
  4. provide listening to changes and actions (menu, toolbar).

Views depend on the windowing system.

In old times, windowing systems were X-Windows on UNIX, or WINDOWS SDK on Microsoft. In other words, you had to implement your user-interface twice when you wanted to deploy your application on both operating systems!

Thanks to the glorious work of Sun engineers we then got Java, running on all popular operating systems. Right from the start the AWT windowing-system was available with Java, and since 1999 Swing, which provided also trees and tables, all platform-independent. SWT followed (IBM). Swing is frozen now, its successor being JavaFX.

Then web browser applications got more and more popular, and views were regarded to be HTML pages enriched with JavaScript to communicate with a web-server.

Next step will be user-interfaces implemented completely in JavaScript, taking all the presentation-logic with it into the web client.

Views need to map the model, thus they implicitly depend on it. When the type of the model was changed and properties were added, most likely also the view will have to support these new properties.
But a view can have less or more fields than the model has properties. For example, a date-property could require three fields for year, month and day. Or the age of a person is rendered on the UI, calculated from its birthday, having no model representation.

A view sometimes needs to convert data-types of fields. E.g. string-to-date conversions are needed for windowing systems that do not support date-choosers.

The Passive View pattern tells us that a view should not contain any presentation-logic. (Else a Swing view could not be exchanged with a web view without duplicating code.) All presentation logic should be in the controller. The view just fires an event to the controller when something has been done, it does not care about what has been done.

Controller

Responsibilities:
  1. listen to view changes and actions,
  2. write changes (received through view events) to the model,
  3. manipulate the data visibility (e.g. enable and disable fields),
  4. load new models into the view.

The most complex of the three. I called it "view wrapper", but it is also on top of MVC, i.e. it represents the MVC.

We could regard the controller to be a collection of actions (an action being "Add", "Delete", "Save", "Refresh" etc). These actions need to be rendered on the view as menu items and buttons, and to be listened to.

The controller is a stateful object, e.g. when a drag & drop starts, it tracks the ongoing action by tracking the dragged item, highlighting hovered items, showing stop-icons, etc.

All presentation-logic must be in the controller, including "cross-field-logics". For example, when the user activates a certain checkbox, a text-field must be enabled to provide detail information. Or, when the user selects an item in a choice, another choice must be filled with different items.

Last not least, events fired by the view that can not be dispatched (e.g. "Close") must be escalated to a parent controller (parent in the sense of composition, not inheritance).

Approach

Here is a way to evolve an MVC:

  • write a model that covers the use-case,
  • write a view, add titles, labels, tooltips to describe it,
  • write the read-only data-binding from model to view, you already can test the MVC now,
  • write the controller to get a writeable MVC.

Resume

I hope I could give an impression of what MVC is. Significant is the event-queue from model to view. That means, changes in the view are done by model events, triggered by the controller having received view events. Kind of control circle.

My next Blog will continue this topic: an MVP view does not listen to the model!




Keine Kommentare: