Factory Method – crearea flexibilă de obiecte fără a cunoaște clasa exactă

  • Doru Bulubasa
  • 03 November 2025

Unul dintre cele mai utile modele de proiectare din categoria Creational Patterns este Factory Method.

Acest pattern ne permite să creăm obiecte fără a specifica exact ce clasă va fi instanțiată, oferind o modalitate elegantă de a extinde codul fără a-l modifica.


🧩 Ce este Factory Method

În programarea orientată pe obiecte, deseori avem nevoie să creăm obiecte dintr-o familie de tipuri similare.

Folosirea directă a new pentru fiecare tip concret face codul rigid și dificil de extins.

Factory Method vine cu o soluție elegantă: definește o interfață sau o clasă abstractă care declară o metodă de creare a obiectelor, iar subclasele decid ce tip concret va fi instanțiat.

Scopul este simplu: separarea codului de creare a obiectelor de codul care le utilizează.


⚙️ Exemplu practic în C#

Imaginăm un scenariu simplu: vrem să construim un sistem de notificări care poate trimite mesaje prin Email sau SMS.

Fără Factory Method, codul ar arăta așa:

public class NotificationService
{
    public void Send(string type, string message)
    {
        if (type == "email")
            new EmailNotifier().Notify(message);
        else if (type == "sms")
            new SmsNotifier().Notify(message);
    }
}

Problema?

Dacă vrem să adăugăm o nouă notificare (ex: Push), trebuie să modificăm codul existent — lucru care contrazice principiul Open/Closed (Open for extension, closed for modification).


🏗️ Implementare corectă cu Factory Method

Aplicăm Factory Method pentru a delega procesul de creare a notificatorului către o clasă derivată:

public abstract class NotificationFactory
{
    public abstract INotifier CreateNotifier();
}

public class EmailNotificationFactory : NotificationFactory
{
    public override INotifier CreateNotifier() => new EmailNotifier();
}

public class SmsNotificationFactory : NotificationFactory
{
    public override INotifier CreateNotifier() => new SmsNotifier();
}

Interfața comună:

public interface INotifier
{
    void Notify(string message);
}

public class EmailNotifier : INotifier
{
    public void Notify(string message) =>
        Console.WriteLine($"📧 Email: {message}");
}

public class SmsNotifier : INotifier
{
    public void Notify(string message) =>
        Console.WriteLine($"📱 SMS: {message}");
}

Utilizare:

NotificationFactory factory = new EmailNotificationFactory();
var notifier = factory.CreateNotifier();
notifier.Notify("Mesaj trimis prin Factory Method!");

Dacă vrem să schimbăm tipul de notificare, schimbăm doar fabrica, nu și logica aplicației.


💡 Avantaje ale Factory Method

Extensibilitate – putem adăuga noi tipuri de obiecte fără a modifica codul existent.

Separare clară între logica de creare și utilizare.

Aplicabil în testare – putem injecta fabrici mock pentru a simula comportamente.

Respectă principiile SOLID, în special Open/Closed și Single Responsibility.


⚠️ Când să eviți Factory Method

Deși elegant, Factory Method poate complica inutil codul pentru scenarii simple.

Dacă ai doar una-două clase concrete și nu plănuiești extensii, o instanțiere directă cu new poate fi suficientă.

Totuși, pe măsură ce aplicația crește, Factory Method devine esențial pentru arhitecturi scalabile și ușor de întreținut.


🧠 Factory Method vs Abstract Factory

Deseori, Factory Method este confundat cu Abstract Factory.

Diferența este că Factory Method se ocupă cu crearea unui singur produs, în timp ce Abstract Factory produce familii de obiecte compatibile (vom discuta acest model într-un articol viitor).


🚀 Concluzie

Factory Method este un pilon de bază al arhitecturii orientate pe obiecte.

El oferă o metodă elegantă de a crea obiecte fără a depinde de clasele lor concrete, permițând codului să fie ușor de extins, testat și întreținut.

În lumea .NET, acest model se regăsește des în frameworkuri precum ASP.NET, Blazor sau Entity Framework, unde fabricile gestionează servicii, componente și obiecte dinamice.

Scrie un comentariu

Adresa de mail nu va fi publicata. Campurile obligatorii sunt marcate cu *