Model-View-Controller
The Model-View-Controller (MVC) is one of the classic architectural patterns from the book “Pattern-Oriented Software Architecture, Volume 1“. It addresses interactive applications with a flexible human-machine interface.
The MVC divides the program logic of a user interface into separate components model, view, and controller. The model manages the data and rules of the application. The view represents the data, and the controller interacts with the user.
Model-View-Controller
Purpose
- User interfaces need to be changed frequently
- Different user interfaces must be supported
- The data model is stable
Solution
- The application is divided into the components Model (data model), View (output components), and Controller (input components)
- Multiple output components can use the same data model
Structure
Model
- The central component of the pattern
- Contains the data (and the business logic)
- Is independent of the
View
andController
View
- Is responsible for the representing of the data and user interaction
- Observes the
Model
- A
View
is associated with aController
to manipulate the Model
Controller
- Manages one or more
View
s - Accepts user interactions and prepares them for the
Model
orView
- Observes the
Model
- Implements the update logic
There are two exciting aspects of the MVC: initialization and user input:
Initialization
The following steps happen during the initialization of the MVC:
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
- The model is created, and it initializes its data
- The view is created and observes the Model
- The controller is created and gets references to the model and the view; it observes the model
- The application starts event processing
User Input
In case of a user event, the following steps happen:
- The controller accepts the user input, handles them, and triggers the model
- The model changes its internal data
- The model notifies all views and controllers about the change of the internal data
- The views and controller update themself
- If the PIN is entered incorrectly in an ATM for the third time, this can mean: The display shows that your account is locked. The ATM confiscates your debit card
- The controller continues to process events
Example
The following program mvc.cpp
applies the MVC.
// mvc.cpp #include <iostream> #include <string> #include <unordered_map> class DefectModel { public: // (5) mutable std::unordered_map<std::string, std::string> defects_ = { {"XYZ" , "File doesn't get deleted."}, {"XAB" , "Registry doesn't get created."}, {"ABC" , "Wrong title get displayed."} }; std::string getDefectComponent(const std::string& component) const { return defects_[component]; } int getSummary() const { return defects_.size(); } std::unordered_map<std::string, std::string> getAllDefects() const { return defects_; } }; class DefectView { public: void showSummary(int num) const { std::cout << "Their are " + std::to_string(num) + " defects in total!\n"; } void showDefectComponent(const std::string& defect) const { std::cout << "Defect of component: " + defect + '\n'; } void showDefectList(const std::unordered_map<std::string, std::string>& defects) const { for (const auto& p: defects) { std::cout << "(" + p.first + ", " + p.second + ")\n"; } } }; class DefectController { const DefectModel& defectModel; const DefectView& defectView; public: DefectController(const DefectModel& defModel, const DefectView& defView): defectModel{defModel}, defectView{defView} { } void showDefectComponent(const std::string& component) const { defectView.showDefectComponent(defectModel.getDefectComponent(component)); // (6) } void showDefectSummary() const { defectView.showSummary(defectModel.getSummary()); // (7) } void showDefectList() const { defectView.showDefectList(defectModel.getAllDefects()); // (8) } }; int main() { std::cout << '\n'; DefectModel defectModel; DefectView defectView; DefectController defectController(defectModel, defectView); // (1) defectController.showDefectComponent("ABC"); // (2) std::cout << '\n'; defectController.showDefectSummary(); // (3) std::cout << '\n'; defectController.showDefectList(); // (4) std::cout << '\n'; }
The controller gets its model and view in its constructor (line 1) and displays its defect list defects
_ (line 5) in three ways (lines 2 – 4). The controller triggers each call in the function and uses its view to display the data given by the model (lines 6 – 8).
The following screenshot shows the output of the program:
Variation
Presentation-Abstraction-Control is an additional pattern from “Pattern-Oriented Software Architecture, Volume 1“, similar to the MVC. It used a hierarchical structure of agents, each agent consisting of the presentation, abstraction(model), and data control. The agents communicate with each other through the control.
Pros and Cons
Pros
- Separation of concern: The Model is strictly separated from the Controller and the Views. Therefore, many views or controllers can be supported concurrently and changed at run time.
- The views as synchronized because they are updated at the same time.
Cons
- The MVC may be too complex and overkill for a small human-machine interface.
- A modification in the model may trigger a cascade of operations on its dependent views and controllers.
- The view and the controller are strongly coupled. A modification of one of them may break the other.
What’s Next?
Event-driven applications, such as GUIs or servers, often apply the architecture pattern Reactor. A Reactor can accept multiple requests simultaneously and distribute them to different handlers.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery, Matt Godbolt, and Honey Sukesan.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | |
My special thanks to PVS-Studio | |
My special thanks to Tipi.build | |
My special thanks to Take Up Code | |
My special thanks to SHAVEDYAKS |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!