Sobes.tech
Junior

Czym jest wzorzec architektoniczny MVC?

sobes.tech AI

Odpowiedź od AI

MVC (Model-View-Controller) to wzorzec architektoniczny, który dzieli aplikację na trzy powiązane ze sobą części, aby poprawić organizację kodu i ułatwić rozwój oraz utrzymanie:

  • Model: Reprezentuje dane i logikę biznesową. Odpowiada za pobieranie, przechowywanie i przetwarzanie danych, a także za zasady nimi rządzące. Nie ma bezpośredniego widoku interfejsu użytkownika.
  • Widok: Odpowiada za wyświetlanie danych użytkownikowi. Pobiera dane z Modelu i wizualizuje je. Nie zawiera logiki biznesowej i nie wchodzi w bezpośrednią interakcję z danymi, oprócz ich renderowania.
  • Kontroler: Działa jako pośrednik między Modelem a Widokiem. Obsługuje interakcję z użytkownikiem (np. kliknięcia, wprowadzanie danych), pobiera dane z Modelu, przekazuje je do Widoku do wyświetlenia i aktualizuje Model w przypadku zmian danych wywołanych przez użytkownika.

Główne relacje:

  • Użytkownik wchodzi w interakcję z Widokiem.
  • Widok przekazuje działania użytkownika Kontrolerowi.
  • Kontroler obsługuje działania użytkownika, wchodząc w interakcję z Modelem (żądając lub aktualizując dane).
  • Model powiadamia Kontroler (lub bezpośrednio Widok, w niektórych wariantach wzorca) o zmianach danych.
  • Kontroler aktualizuje Widok na podstawie zmian w Modelu (lub Widok aktualizuje się samodzielnie przy bezpośredniej interakcji z Modelem).

Zalety:

  • Podział odpowiedzialności: Ułatwia rozwój, testowanie i utrzymanie poszczególnych komponentów.
  • Ponowne użycie kodu: Model i Kontroler mogą być używane z różnymi Widokami.
  • Ułatwienie testowania: Komponenty mogą być testowane niezależnie.
  • Równoległy rozwój: Różne zespoły mogą pracować nad różnymi częściami (Model, Widok, Kontroler) jednocześnie.

Wady:

  • Zwiększenie złożoności: Może być nadmierne dla małych aplikacji.
  • Problem "Fat Controller": Kontroler może stać się zbyt duży i skomplikowany, jeśli nie przestrzega się zasad podziału.
  • Trudność w określeniu granic: Czasami trudno wyraźnie określić, gdzie kończy się jeden komponent, a zaczyna inny.

Przykład (schematyczny):

// Model (np. klasa do pracy z danymi)
class UserModel {
  constructor() {
    this.users = [{
      id: 1,
      name: 'Alice'
    }, {
      id: 2,
      name: 'Bob'
    }];
  }

  getUsers() {
    return this.users;
  }

  addUser(user) {
    this.users.push(user);
    // Powiadomienie o zmianie (w rzeczywistej aplikacji - przez zdarzenia)
  }
}

// Widok (np. funkcja do renderowania listy)
function renderUserList(users) {
  const list = document.getElementById('user-list');
  list.innerHTML = users.map(user => `<li>${user.name}</li>`).join('');
}

// Kontroler (do obsługi zdarzeń i koordynacji)
class UserController {
  constructor(model, view) {
    this.model = model;
    this.view = view;

    // Inicjalizacja widoku
    this.updateView();

    // Obsługa zdarzeń (np. kliknięcie przycisku)
    document.getElementById('add-user-button').addEventListener('click', () => {
      const newUser = {
        id: this.model.getUsers().length + 1,
        name: prompt('Enter user name:')
      };
      if (newUser.name) {
        this.model.addUser(newUser);
        this.updateView(); // Aktualizacja widoku po zmianie modelu
      }
    });
  }

  updateView() {
    const users = this.model.getUsers();
    this.view(users);
  }
}

// Użycie
const model = new UserModel();
const controller = new UserController(model, renderUserList);

To uproszczony przykład demonstrujący podstawową zasadę. W rzeczywistych frameworkach (takich jak Angular, React, Vue) stosuje się bardziej zaawansowane warianty tego i innych wzorców architektonicznych.