Factory och Strategy
När du läst detta ska du kunna
- Förklara varför Factory-mönstret finns
- Skriva en enkel factory-metod
- Förklara Strategy-mönstret och peka ut det i .NET du redan använt
Factory — flytta ut new
Problemet: kod som anropar new ConcreteClass() direkt är hårt kopplad till den exakta typen. Byter du implementation måste du hitta och ändra varje new-anrop.
public interface INotifier{ void Send(string message);}
public class EmailNotifier : INotifier{ public void Send(string message) => Console.WriteLine($"E-post: {message}");}
public class SmsNotifier : INotifier{ public void Send(string message) => Console.WriteLine($"SMS: {message}");}
public static class NotifierFactory{ public static INotifier Create(string kanal) => kanal switch { "email" => new EmailNotifier(), "sms" => new SmsNotifier(), _ => throw new ArgumentException($"Okänd kanal: {kanal}") };}INotifier notifier = NotifierFactory.Create("email");notifier.Send("Din beställning har skickats.");Anroparen bryr sig bara om INotifier — vilken konkret klass som faktiskt skapas är factoryns beslut, inte anroparens. Lägger du till en PushNotifier senare ändrar du bara factoryn, aldrig koden som använder notifiers.
Strategy — byt algoritm vid körning
Problemet: du behöver flera sätt att göra samma sak (sortera, validera, beräkna pris), och vill kunna byta metod utan if/switch-kedjor utspridda i koden.
public interface IRabattStrategi{ decimal BeräknaRabatt(decimal pris);}
public class ingenRabatt : IRabattStrategi{ public decimal BeräknaRabatt(decimal pris) => 0;}
public class ProcentRabatt : IRabattStrategi{ private readonly decimal _procent; public ProcentRabatt(decimal procent) => _procent = procent; public decimal BeräknaRabatt(decimal pris) => pris * _procent;}
public class Order{ public decimal Pris { get; set; } public IRabattStrategi Rabatt { get; set; } = new ingenRabatt();
public decimal SlutPris() => Pris - Rabatt.BeräknaRabatt(Pris);}var order = new Order { Pris = 1000, Rabatt = new ProcentRabatt(0.2m) };Console.WriteLine(order.SlutPris()); // 800Bytet av strategi sker genom att sätta en annan implementation — inte genom att skriva om Order.
Du har redan använt Strategy
Det här mönstret är inbyggt i .NET på flera ställen du redan känner till:
List<int> tal = new() { 5, 2, 8, 1 };
tal.Sort((a, b) => b.CompareTo(a)); // Strategy: sortera fallande, via ett Comparison<T>-delegat
var namn = personer.OrderBy(p => p.Ålder); // Strategy: sorteringsnyckeln är utbytbarComparison<T> som du skickar till .Sort(), och nyckelfunktionen du skickar till .OrderBy() i LINQ, är strategier — utbytbara algoritmer som injiceras istället för att hårdkodas. IComparer<T> är samma idé uttryckt som ett interface istället för ett delegat.
TL;DR
Factory flyttar ansvaret för att skapa objekt bort från koden som använder dem — byt implementation på ett ställe. Strategy gör en algoritm utbytbar vid körning — du har redan använt det varje gång du skickat ett lambda-uttryck till .Sort() eller .OrderBy().