MVC — Smalltalk 1979
Del 1 av UI-arkitektur. Här börjar allt. Modellen
Kundvagnsom används här finns i översikten.
När du läst detta ska du kunna
- Förklara de tre rollerna i klassisk MVC och vem som pratar med vem
- Förklara varför modellen inte känner till vyn
- Känna igen Observer-mönstret i MVC
Bakgrund och idé
Trygve Reenskaug formulerade MVC på Xerox PARC 1979 för Smalltalk. Problemet han löste: grafiska gränssnitt var nytt, och koden för att rita blandades med koden för att reagera på musen och datan själv. Lösningen blev tre roller med var sitt ansvar.
graph LR
U((Användare)) -->|tangent / mus| C[Controller]
C -->|anropar metod| M[Model]
M -.->|event: Ändrad| V[View]
V -->|läser data| M
V -->|ritar| U
Så läser du diagrammet
- Användaren trycker på en tangent. Det är Controllern som tar emot input — inte vyn.
- Controllern översätter input till ett anrop på Modellen (
LäggTill,TaBort). Controllern har ingen egen data. - Modellen ändrar sig själv och skickar ut ett event (streckad pil = “jag säger bara till, jag vet inte vem som lyssnar”).
- Vyn prenumererar på eventet, läser den nya datan direkt från modellen och ritar om sig.
Det viktiga: modellen känner inte till vyn. Du kan ha tre vyer av samma modell (en lista, en summa, en ikon) och alla uppdateras automatiskt.
// Vyn prenumererar på modellen och ritar om sig när den ändraspublic class KundvagnVy{ public KundvagnVy(Kundvagn modell) { modell.Ändrad += () => Console.WriteLine($"[Vy] Antal: {modell.Varor.Count} – {string.Join(", ", modell.Varor)}"); }}
// Controllern översätter användarens input till anrop på modellenpublic class KundvagnController{ private readonly Kundvagn _modell;
public KundvagnController(Kundvagn modell) => _modell = modell;
public void HanteraKommando(string rad) { // "+mjölk" lägger till, "-mjölk" tar bort if (rad.StartsWith('+')) _modell.LäggTill(rad[1..]); else if (rad.StartsWith('-')) _modell.TaBort(rad[1..]); }}var modell = new Kundvagn();var vy = new KundvagnVy(modell);var controller = new KundvagnController(modell);
foreach (var kommando in new[] { "+mjölk", "+bröd", "-mjölk" }) controller.HanteraKommando(kommando);
// [Vy] Antal: 1 – mjölk// [Vy] Antal: 2 – mjölk, bröd// [Vy] Antal: 1 – brödMappstruktur
i en liten konsolapp räcker det med en mapp per roll:
KundvagnMvc/├── Models/│ └── Kundvagn.cs├── Views/│ └── KundvagnVy.cs├── Controllers/│ └── KundvagnController.cs└── Program.cs ← kopplar ihop de tre