Factory Method (Fabriksmetod)
Introduktion
Factory Method är ett skapande mönster som definierar ett gränssnitt för att skapa objekt, men låter underklasser bestämma vilken klass som ska instansieras.
Problem
Du bygger ett logistiksystem. I den första versionen hanterar appen bara lastbilstransporter, och koden är full av new Truck()-anrop.
När kunden vill lägga till sjöfrakt måste du gå igenom hela kodbasen. Och när flygtransport tillkommer? Samma sak igen.
Lösning
Factory Method ersätter direkta konstruktoranrop med ett anrop till en fabriksmetod. Underklassen bestämmer vilken konkret klass som skapas. Klientkoden ser bara gränssnittet.
När ska Factory Method användas?
- När du inte vet i förväg exakt vilka klasser din kod ska arbeta med.
- När du vill ge användare av ditt bibliotek möjlighet att utöka dess komponenter.
- För att minska beroenden av konkreta klasser.
Struktur
| Roll | Ansvar |
|---|---|
| Creator | Deklarerar fabriksmetoden; kan ha en default-implementation. |
| Concrete Creator | Överskuggar fabriksmetoden och returnerar en specifik produkt. |
| Product Interface | Definierar gränssnittet för alla produkter. |
| Concrete Product | En specifik implementation av produktgränssnittet. |
Exempel — Logistiksystem (C# / .NET)
Scenariot: Ett logistiksystem som skapar transportobjekt via en fabriksmetod.
// ── Product Interface ─────────────────────────────────────
public interface ITransport
{
void Deliver(string origin, string destination);
}
// ── Concrete Products ─────────────────────────────────────
public class Truck : ITransport
{
public void Deliver(string origin, string destination) =>
Console.WriteLine($"🚛 Lastbil levererar: {origin} → {destination} (via landsväg)");
}
public class Ship : ITransport
{
public void Deliver(string origin, string destination) =>
Console.WriteLine($"🚢 Fartyg levererar: {origin} → {destination} (via havsrutt)");
}
public class Airplane : ITransport
{
public void Deliver(string origin, string destination) =>
Console.WriteLine($"✈️ Flygplan levererar: {origin} → {destination} (direktflyg)");
}
// ── Creator (abstrakt) ────────────────────────────────────
public abstract class Logistics
{
// Fabriksmetoden — underklassen bestämmer vad som skapas
public abstract ITransport CreateTransport();
// Affärslogiken använder produkten via gränssnittet
public void PlanDelivery(string origin, string destination)
{
ITransport transport = CreateTransport();
Console.WriteLine("Planerar leverans...");
transport.Deliver(origin, destination);
}
}
// ── Concrete Creators ─────────────────────────────────────
public class RoadLogistics : Logistics
{
public override ITransport CreateTransport() => new Truck();
}
public class SeaLogistics : Logistics
{
public override ITransport CreateTransport() => new Ship();
}
public class AirLogistics : Logistics
{
public override ITransport CreateTransport() => new Airplane();
}
// ── Klientkod ─────────────────────────────────────────────
static Logistics GetLogistics(string mode) => mode switch
{
"road" => new RoadLogistics(),
"sea" => new SeaLogistics(),
_ => new AirLogistics(),
};
// Klienten väljer Creator — inte konkret produkt
Logistics logistics = GetLogistics("sea");
// Klientkoden behöver inte ändras när nya transporttyper läggs till
logistics.PlanDelivery("Stockholm", "Hamburg");
Output:
Planerar leverans...
🚢 Fartyg levererar: Stockholm → Hamburg (via havsrutt)
Fördelar
- Single Responsibility Principle — Produktskapandet är på ett ställe.
- Open/Closed Principle — Lägg till nya produkttyper utan att ändra klientkoden.
- C#
switchexpression gör Creator-logiken kortfattad och läsbar.
Nackdelar
- Koden kan bli mer komplex med många underklasser.
Av Victor Hernandez från Bytebase.se