Visitor
Problemet
Du har en objektstruktur (filer och mappar, olika sorters element i ett dokument) och vill lägga till nya operationer på den (beräkna total storlek, exportera till XML, validera) — utan att lägga till en ny metod i varje klass i strukturen varje gång du behöver en ny operation.
Lösningen
public interface IElement{ void Accept(IVisitor visitor);}
public interface IVisitor{ void Visit(Fil fil); void Visit(Mapp mapp);}
public class Fil : IElement{ public string Namn { get; } public int StorlekKb { get; } public Fil(string namn, int storlekKb) => (Namn, StorlekKb) = (namn, storlekKb);
public void Accept(IVisitor visitor) => visitor.Visit(this); // Vet bara att "besökas"}
public class Mapp : IElement{ public string Namn { get; } public List<IElement> Innehåll { get; } = new(); public Mapp(string namn) => Namn = namn;
public void Accept(IVisitor visitor) => visitor.Visit(this);}
// Den nya operationen lever HÄR — inte utspridd i Fil och Mapppublic class StorleksVisitor : IVisitor{ public int TotalStorlek { get; private set; }
public void Visit(Fil fil) => TotalStorlek += fil.StorlekKb;
public void Visit(Mapp mapp) { foreach (var element in mapp.Innehåll) element.Accept(this); // Besök varje element i mappen rekursivt }}var rot = new Mapp("Dokument");rot.Innehåll.Add(new Fil("rapport.pdf", 500));rot.Innehåll.Add(new Fil("bild.png", 1200));
var visitor = new StorleksVisitor();rot.Accept(visitor);Console.WriteLine(visitor.TotalStorlek); // 1700Vill du lägga till en ny operation — t.ex. räkna antal filer — skriver du en ny IVisitor-implementation. Fil och Mapp ändras aldrig.
Avvägningen
Visitor gör det enkelt att lägga till nya operationer utan att röra Fil/Mapp, men priset är motsatsen: lägger du till en ny elementtyp (t.ex. Genväg) måste du uppdatera IVisitor och alla dess implementationer. Använd Visitor när elementstrukturen är stabil men operationerna växer — inte tvärtom.
TL;DR
Visitor flyttar en operation som annars skulle sprids ut över flera klasser till en egen klass — nya operationer blir nya Visitor-klasser istället för nya metoder i varje elementklass. Bäst när strukturen är stabil men antalet operationer växer.