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

RollAnsvar
CreatorDeklarerar fabriksmetoden; kan ha en default-implementation.
Concrete CreatorÖverskuggar fabriksmetoden och returnerar en specifik produkt.
Product InterfaceDefinierar gränssnittet för alla produkter.
Concrete ProductEn 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# switch expression 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