mvc


 * Course:** SSE658
 * Project:** 3
 * Subject:** Model-View-Controller Pattern
 * Student:** Dmitriy Slipak
 * E-mail:** dslipak@gmail.com

=Table Of Content=

Definition Classification Intent Motivation Applicability Structure Participants Advantages Disadvantages Implementation Example Conclusion References

 =Definition=

Model–View–Controller (MVC) is a software architecture, currently considered as an architectural pattern used in software engineering. The pattern isolates "domain logic" (the application logic for the user) from input and presentation (GUI), permitting independent development, testing and maintenance of each.

The MVC paradigm was originated by Trygve Reenskaug in 1978 during his work at Xerox PARC. The essential purpose of MVC is to bridge the gap between the human user's mental model and the digital model that exists in the computer. The ideal MVC solution supports the user illusion of seeing and manipulating the domain information directly. The structure is useful if the user needs to see the same model element simultaneously in different contexts and/or from different viewpoints. The figure below illustrates the idea.

 =Classification=

Object Behavioral Pattern  =Intent=

The MVC pattern divides an interactive application into three components. The model contains the core functionality and data. Views display information to the user. Controllers handle user input. Views and controllers together comprise the user interface. A change-propagation mechanism ensures consistency between the user interface and the model.  =Motivation=

MVC divides an interactive application into three areas: processing, output, and input. The model component encapsulates core data and functionality. The model is independent of specific output representations or input behavior. View components display information to the user. A view obtains the data from the model. There can be multiple views of the model. Each view has an associated controller component. Controllers receive input, usually as events that encode mouse movement, activation of mouse buttons, or keyboard input. Events are translated to service requests for the model or the view. The user interacts with the system solely through controllers. The separation of the model from view and controller components allows multiple views of the same model. If the user changes the model via the controller of one view all other views dependent o this data should reflect the changes. The model therefore notifies all views whenever its data changes. The views in turn retrieve new data from the model and update the displayed information.  =Applicability=

The MVC pattern might be used:

 =Structure=
 * Almost in every application. Depending on the application, some classes might be coupled tighter than others, however it is generally always a good idea to structure an application according to MVC.

The solid line represents a direct association, the dashed an indirect association.  =Participants=


 * **Model** - used to manage information and notify observers when that information changes. It contains only data and functionality that are related by a common purpose. If we need to model two groups of unrelated data and functionality, we create two separate models.

> A model encapsulates more than just data and functions that operate on it. A model is meant to serve as a computational approximation or abstraction of some real world process or system. It captures not only the state of a process or system, but how the system works. This makes it very easy to use real-world modeling techniques in defining models.
 * **View** - responsible for mapping graphics onto a device. A view typically has a one to one correspondence with a display surface and knows how to render to it. A view attaches to a model and renders its contents to the display surface. In addition, when the model changes, the view automatically redraws the affected part of the image to reflect those changes. There can be multiple views onto the same model and each of these views can render the contents of the model to a different display surface.

> A view may be a composite view containing several sub-views, which may themselves contain several sub-views.  =Advantages=
 * **Controller** - the means by which the user interacts with the application. A controller accepts input from the user and instructs the model and view to perform actions based on that input. In effect, the controller is responsible for mapping end-user action to application response. For example, if the user clicks the mouse button or chooses a menu item, the controller is responsible for determining how the application should respond.

 =Disadvantages=
 * Enhanced maintainability and extensibility of the system.
 * Multiple views of the same model.
 * Plug-gable views and controllers.
 * Code reuse.
 * Synchronized views.

 =Implementation=
 * Complexity of design and implementation.
 * Data transformation overhead.
 * Observers are unaware of each other - causing problems changing state of the subject potential for excessive number of updates.

The MVC pattern usually incorporates Observer Pattern and Strategy Pattern.

Classic implementation of the Model-View-Controller pattern consists of three abstract superclasses named Model, View, and Controller, plus numerous concrete subclasses. The abstract classes hold the generic behavior and state of the three parts of MVC. The concrete classes hold the specific state and behavior of the application facilities and user interface components.  =Example=

Here is simple implementation of the MVC pattern. Please note, the example below requires FLTK library.

Note on Building and Using FLTK library
Here are few steps required to be able run the MVC example.


 * 1) Download the FLTK source code. At the moment of this writing stable version is 1.1.10.
 * 2) Compile the fltk source code. I was able successfully compile it under MS Visual C++ 2008 Express Edition using the source located in "vc2005" directory.
 * 3) Copy all the compiled libraries, except "README.lib" from "lib" folder into $(VCInstallDir)\lib (my path is "C:\Program Files\Microsoft Visual Studio 9.0\VC\lib") folder.
 * 4) Copy entire "FL" folder into $(VCInstallDir)\include folder.
 * 5) Edit your project's properties as follows. Go to "Project Properties->Configuration Properties->Linker->Additional Dependencies" and add following libraries: fltk.lib comctl32.lib wsock32.lib

Below is complete source code for the example.

Module mvc.h
code format="C++" // Module:       mvc.h // Programmer:    Dmitriy Slipak // Date:       March 02, 2010 // Purpose: //               Header file, //               contains MVC pattern classes declaration //
 * 1) ifndef _MVC_H_
 * 2) define _MVC_H_


 * 1) include
 * 2) include
 * 3) include 
 * 4) include 
 * 5) include 
 * 6) include 

const int PIE_COLOR = 1;   //    red color const int DEFAULT_VIEW_W = 400; const int DEFAULT_VIEW_H = 300; const int PIE_DIAMETER = 120; const int MAX_PIE_W = 200; const int PIE_RESIZE_STEP = 10;

//   Pie class, derived from Fl_Widget struct Pie : public Fl_Widget {   //    Pie ctor, must initialize Fl_Widget Pie(int x, int y, int w, int h) : Fl_Widget(x, y, w, h) { }

void draw; void print_size;

inline int get_x { return x; } inline int get_y { return y; } inline int get_w { return w; } inline int get_h { return h; }

void set_x(const int& value); void set_y(const int& value); void set_w(const int& value); void set_h(const int& value); };

class Subject;

class Observer { public: virtual void update(Subject* s) = 0; };

class Subject { private: std::list observers;

public: void set_message(std::string m);

virtual void subscribe(Observer* o); virtual void unsubscribe(Observer* o); virtual void notify; };

//   Model class, represents simple data holder struct Model : public Subject {   int x;    int y;    int w;    int h;

Model { x = y = w = h = 0; }

inline int get_x { return x; } inline int get_y { return y; } inline int get_w { return w; } inline int get_h { return h; }

void set_x(const int& value); void set_y(const int& value); void set_w(const int& value); void set_h(const int& value); };

class View;   //    View class forward declaration

class Controller : public Observer { private: Model* model; View* view;

protected: std::list subjects;

public: Controller(Model* m); ~Controller;

void subscribe(Subject* s); void unsubscribe(Subject* s); void update(Subject* s);

void increase_pie(const int& value); void decrease_pie(const int& value); };

class View : public Fl_Window, public Observer { private: Model* model; Controller* controller; Fl_Button* btn_plus; Fl_Button* btn_minus; Pie* pie;

inline static void btn_plus_cb(Fl_Widget* widget, void* data) {       ((View*)data)->increase_pie(PIE_RESIZE_STEP); }

inline static void btn_minus_cb(Fl_Widget* widget, void* data) {       ((View*)data)->decrease_pie(PIE_RESIZE_STEP); }

inline void increase_pie(int value) {       controller->increase_pie(PIE_RESIZE_STEP); }

inline void decrease_pie(int value) {       controller->decrease_pie(PIE_RESIZE_STEP); }

protected: std::list subjects;

public: View(int w, int h, const char* t, Model* m, Controller* c); ~View;

inline void activate(Fl_Widget* widget) { widget->activate; } inline void deactivate(Fl_Widget* widget) { widget->deactivate; }

Fl_Widget* get_btn_plus { return btn_plus; } Fl_Widget* get_btn_minus { return btn_minus; }

void run; void subscribe(Subject* s); void unsubscribe(Subject* s); void update(Subject* s); };

code
 * 1) endif

Module mvc.cpp
code format="C++" // Module:       mvc.cpp // Programmer:   Dmitriy Slipak // Date:       March 02, 2010 // Purpose: //               MVC pattern classes implementation //
 * 1) include "mvc.h"

/// ///   Subject class implementation /// void Subject::subscribe(Observer* o) { observers.push_back(o); } void Subject::unsubscribe(Observer* o) { observers.remove(o); }

void Subject::notify {   std::list::iterator iter;

for(iter=observers.begin; iter != observers.end; ++iter) ((Observer*)*iter)->update(this); }

/// ///   Pie class implementation ///

//   draw override void Pie::draw {   fl_color(PIE_COLOR); fl_pie(x, y, w, h, 0.0, 360.0); activate; }

void Pie::print_size {   std::cout << "x: " << x << std::endl << "y: " << y << std::endl << "w: " << w << std::endl << "h: " << h << std::endl << std::endl; }

void Pie::set_x(const int& value) { deactivate; x(value); redraw; } void Pie::set_y(const int& value) { deactivate; y(value); redraw; } void Pie::set_w(const int& value) { deactivate; w(value); redraw; } void Pie::set_h(const int& value) { deactivate; h(value); redraw; }

/// ///   Model class implementation /// void Model::set_x(const int& value) { x = value; notify; } void Model::set_y(const int& value) { y = value; notify; } void Model::set_w(const int& value) { w = value; notify; } void Model::set_h(const int& value) { h = value; notify; }

/// ///   Controller class implementation ///

Controller::Controller(Model* m) { model = m;   view = new View(DEFAULT_VIEW_W, DEFAULT_VIEW_H, "MVC", model, this);

subscribe(model); view->run; }

Controller::~Controller {   delete view; }

void Controller::increase_pie(const int& value) {   model->set_x(model->get_x-value/2); model->set_y(model->get_y-value/2); model->set_w(model->get_w+value); model->set_h(model->get_h+value); }

void Controller::decrease_pie(const int& value) {   model->set_x(model->get_x+value/2); model->set_y(model->get_y+value/2); model->set_w(model->get_w-value); model->set_h(model->get_h-value); }

void Controller::subscribe(Subject* s) { subjects.push_back(s); s->subscribe(this); }

void Controller::unsubscribe(Subject* s) { subjects.remove(s); s->unsubscribe(this); }

void Controller::update(Subject* s) { std::list::iterator iter;

for(iter=subjects.begin; iter != subjects.end; ++iter) { if (s != (Subject*)* iter) continue; if (view == 0) break; if (model->get_w <= 0) view->deactivate(view->get_btn_minus); else view->activate(view->get_btn_minus);

if (model->get_w >= MAX_PIE_W) view->deactivate(view->get_btn_plus); else view->activate(view->get_btn_plus); } }

/// ///   View class implementation ///

View::View(int w, int h, const char* t, Model* m, Controller* c) : Fl_Window(w, h, t) { model = m;   controller = c;    subscribe(model);

btn_plus = new Fl_Button(w/2-35, 10, 30, 20, "+"); btn_minus = new Fl_Button(w/2+5, 10, 30, 20, "-"); pie = new Pie(model->get_x, model->get_y, model->get_w, model->get_h);

//   initialize model, set default size model->set_x(w/2-PIE_DIAMETER/2); model->set_y(h/2-PIE_DIAMETER/2); model->set_w(PIE_DIAMETER); model->set_h(PIE_DIAMETER);

end;   //    end of controls placed on FLTK window

//   initialize callback functions for buttons btn_plus->callback(btn_plus_cb, (void*) this); btn_minus->callback(btn_minus_cb, (void*) this); }

View::~View {   delete btn_plus; delete btn_minus; delete pie; }

void View::run {   show;    //    activate window while (Fl::wait);   //    display window until closed }

void View::subscribe(Subject* s) { subjects.push_back(s); s->subscribe(this); }

void View::unsubscribe(Subject* s) { subjects.remove(s); s->unsubscribe(this); }

void View::update(Subject* s) { std::list::iterator iter;

for(iter=subjects.begin; iter != subjects.end; ++iter) { if (s != (Subject*)* iter) continue;

pie->set_x(model->get_x); pie->set_y(model->get_y); pie->set_w(model->get_w); pie->set_h(model->get_h); pie->print_size; } } code

Module mvc_driver.cpp
code format="C++"
 * 1) include "mvc.h"

int main {   Model* model = new Model; Controller* controller = new Controller(model); delete controller; delete model;

return 0; } code

Sample Run
You can watch the sample run of the example above. Complete source code for this example can be located at the course FTP server, in the folder under my name. media type="youtube" key="pnLdBTeGFq0" width="480" height="400"  =Conclusion=

 =References=

1. The original MVC reports. Trygve Reenskaug - 1979. 2. Wikipedia. 3. Head First Design Patterns by Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates. 2004 - O'Reilly Media, Inc.

Last revision date: {$revisiondate}