Model-View-Controller (MVC)
Model-View-Controller, w skrócie MVC, to wzorzec projektowy stosowany w architekturze oprogramowania, którego celem jest oddzielenie logiki aplikacji od sposobu jej prezentacji oraz interakcji z użytkownikiem. Rozdzielenie to ułatwia utrzymanie, testowanie i rozwój systemu.
Historia
Pierwsze koncepcje MVC zostały sformułowane w latach 1970–1979 w ramach prac nad językiem programowania Smalltalk w laboratoriach Xerox PARC. Autorami modelu byli Trygve Reenskaug oraz jego zespół. Od tego czasu wzorzec został zaadaptowany w wielu frameworkach i językach, m.in. w Ruby on Rails, ASP.NET, Django, Laravel czy Angular.
Podstawowe komponenty
- Model – reprezentuje dane oraz logikę biznesową aplikacji. Odpowiada za dostęp do bazy danych, walidację i przetwarzanie informacji. Model jest niezależny od sposobu ich prezentacji.
- View (Widok) – odpowiada za wyświetlanie danych użytkownikowi. Zawiera szablony, elementy interfejsu użytkownika oraz elementy graficzne. Widok nie posiada logiki biznesowej.
- Controller (Kontroler) – pośredniczy pomiędzy modelem a widokiem. Odebruje żądania HTTP lub akcje użytkownika, wywołuje odpowiednie metody modelu i wybiera widok, który ma zostać zwrócony.
Jak działa MVC?
- Użytkownik wykonuje akcję (np. kliknięcie przycisku) w interfejsie.
- Żądanie trafia do kontrolera, który interpretuje je i decyduje, które operacje na modelu wykonać.
- Model przetwarza dane, ewentualnie odczytuje lub zapisuje je w bazie danych.
- Kontroler otrzymuje wynik od modelu i przekazuje go do odpowiedniego widoku.
- Widok generuje HTML, JSON lub inny format i zwraca go do przeglądarki użytkownika.
Zalety MVC
- Rozdzielenie odpowiedzialności ułatwia modularność i ponowne użycie komponentów.
- Umożliwia równoczesną pracę zespołów: programiści backendu mogą pracować nad modelem i kontrolerem, a designerzy nad widokiem.
- Ułatwia testowanie jednostkowe i integracyjne dzięki wyraźnemu podziałowi.
- Zapewnia lepszą skalowalność aplikacji w miarę rosnącej złożoności.
Wady i ograniczenia
- Wymaga większej liczby plików i warstw, co może wprowadzić dodatkową złożoność w małych projektach.
- Przejście od tradycyjnego podejścia do MVC może wymagać znaczącej refaktoryzacji istniejącego kodu.
- Nie wszystkie aplikacje potrzebują tak silnego rozdzielenia warstw – w prostych narzędziach skrypty mogą być bardziej efektywne.
Zastosowania
MVC jest wykorzystywany w:
- aplikacjach internetowych (webowych),
- aplikacjach desktopowych (JavaFX, WinForms),
- aplikacjach mobilnych (np. iOS z UIKit),
- systemach o dużej skalowalności i wymagających bezpieczeństwa.
Implementacje MVC w popularnych technologiach
| Technologia | Framework | Opis |
|---|---|---|
| Ruby | Ruby on Rails | Klasyczna implementacja MVC z aktywnym modelem (ActiveRecord) i konwencją „convention over configuration”. |
| C# | ASP.NET MVC | Framework Microsoftu umożliwiający budowę aplikacji webowych w stylu MVC, z silnym wsparciem dla testów jednostkowych. |
| Python | Django | Choć nazywany MTV (Model-Template-View), zasadniczo spełnia rolę MVC. |
| PHP | Laravel | Laravel wprowadza wyraźną separację modeli (Eloquent), widoków (Blade) i kontrolerów. |
| Java | Spring MVC | Moduł Spring Framework obsługujący żądania HTTP, mapowanie kontrolerów i integrację z warstwą usług. |
| JavaScript | Angular | Wzrasta rola komponentów, ale architektura opiera się na podziale na modele, szablony i kontrolery. |
Powiązane wzorce
Wśród wzorców projektowych istnieją alternatywy i rozszerzenia MVC:
- Model-View-Presenter (MVP) – prezentuje kontroler (presenter) jako pośrednika w pełni niezależnego od widoku.
- Model-View-ViewModel (MVVM) – wykorzystywany głównie w WPF i Xamarin do dwukierunkowego powiązania danych.
- Hierarchical MVC (HMVC) – wprowadza zagnieżdżone kontrolery, przydatne w dużych aplikacjach.
Przykładowy kod (PHP / Laravel)
// Model: app/Models/Article.php
class Article extends Model {
protected $fillable = ['title', 'content'];
}
// Controller: app/Http/Controllers/ArticleController.php
class ArticleController extends Controller {
public function index() {
$articles = Article::all();
return view('articles.index', compact('articles'));
}
public function show($id) {
$article = Article::findOrFail($id);
return view('articles.show', compact('article'));
}
}
// View: resources/views/articles/index.blade.php
<h1>Lista artykułów</h1>
@foreach ($articles as $article)
<div>
<h2><a href="{{ route('articles.show', $article) }}">{{ $article->title }}</a></h2>
<p>{{ Str::limit($article->content, 150) }}</p>
</div>
@endforeach