DEV Community

Sadel Fortunato
Sadel Fortunato

Posted on

Dia 8: 🧩 Abstract Factory Pattern en C#

¿QUÉ ES ABSTRACT FACTORY?
Es un patron para construir familia de objetos relacionados, esto nos permite crear una interfaz completa con todos los componentes que necesitemos. No necesitamos especificar la clase concreta.

Es un factory de factories

Analogía del Restaurant
Factory Method:
Restaurant → Crea solo HAMBURGUESAS

  • Hamburguesa clásica
  • Hamburguesa vegetariana
  • Hamburguesa premium Abstract Factory: Restaurant → Crea COMIDAS COMPLETAS
  • Entrada + Plato Principal + Postre (Menú Italiano)
  • Entrada + Plato Principal + Postre (Menú Mexicano)
  • Entrada + Plato Principal + Postre (Menú Japonés)

FACTORY METHOD (Un producto)
┌─────────────────────┐
│ TransporteFactory │
└─────────────────────┘

├─ Camión
├─ Barco
└─ Avión

ABSTRACT FACTORY (Familia de productos)
┌─────────────────────┐
│ UIFactory │
└─────────────────────┘

├─ WindowsFactory
│ ├─ Button
│ ├─ Window
│ └─ Checkbox

├─ MacFactory
│ ├─ Button
│ ├─ Window
│ └─ Checkbox

└─ LinuxFactory
├─ Button
├─ Window
└─ Checkbox

ESTRUCTURA DEL PATRÓN
Componentes:

AbstractFactory - Interfaz para crear familias de productos
ConcreteFactory - Implementación específica (ej: WindowsFactory)
AbstractProduct - Interfaz para un tipo de producto (ej: IButton)
ConcreteProduct - Implementación específica (ej: WindowsButton)
Client - Usa solo abstracciones, no clases concretas

Paso 1: Definir AbstractProducts

csharp// Productos abstractos (interfaces)
public interface IButton
{
    void Render();
    void Click();
}

public interface IWindow
{
    void Open();
    void Close();
    void Maximize();
}

public interface ICheckbox
{
    void Render();
    void Check();
    void Uncheck();
}

Paso 2: Crear ConcreteProducts para cada familia
csharp// ========== FAMILIA WINDOWS ==========
public class WindowsButton : IButton
{
    public void Render()
    {
        Console.WriteLine(" Renderizando botón estilo Windows");
    }

    public void Click()
    {
        Console.WriteLine(" Click en botón Windows");
    }
}

public class WindowsWindow : IWindow
{
    public void Open()
    {
        Console.WriteLine("🪟 Abriendo ventana Windows");
    }

    public void Close()
    {
        Console.WriteLine(" Cerrando ventana Windows");
    }

    public void Maximize()
    {
        Console.WriteLine(" Maximizando ventana Windows");
    }
}

public class WindowsCheckbox : ICheckbox
{
    public void Render()
    {
        Console.WriteLine(" Renderizando checkbox Windows");
    }

    public void Check()
    {
        Console.WriteLine(" Checkbox marcado");
    }

    public void Uncheck()
    {
        Console.WriteLine(" Checkbox desmarcado");
    }
}

// ========== FAMILIA MAC ==========
public class MacButton : IButton
{
    public void Render()
    {
        Console.WriteLine(" Renderizando botón estilo Mac");
    }

    public void Click()
    {
        Console.WriteLine(" Click en botón Mac");
    }
}

public class MacWindow : IWindow
{
    public void Open()
    {
        Console.WriteLine("🪟 Abriendo ventana Mac");
    }

    public void Close()
    {
        Console.WriteLine(" Cerrando ventana Mac");
    }

    public void Maximize()
    {
        Console.WriteLine(" Maximizando ventana Mac");
    }
}

public class MacCheckbox : ICheckbox
{
    public void Render()
    {
        Console.WriteLine(" Renderizando checkbox Mac");
    }

    public void Check()
    {
        Console.WriteLine(" Checkbox marcado (estilo Mac)");
    }

    public void Uncheck()
    {
        Console.WriteLine(" Checkbox desmarcado (estilo Mac)");
    }
}

Paso 3: Definir AbstractFactory
csharp// Factory abstracta
public interface IUIFactory
{
    IButton CreateButton();
    IWindow CreateWindow();
    ICheckbox CreateCheckbox();
}
Paso 4: Crear ConcreteFactories
csharp// Factory concreta para Windows
public class WindowsFactory : IUIFactory
{
    public IButton CreateButton()
    {
        return new WindowsButton();
    }

    public IWindow CreateWindow()
    {
        return new WindowsWindow();
    }

    public ICheckbox CreateCheckbox()
    {
        return new WindowsCheckbox();
    }
}

// Factory concreta para Mac
public class MacFactory : IUIFactory
{
    public IButton CreateButton()
    {
        return new MacButton();
    }

    public IWindow CreateWindow()
    {
        return new MacWindow();
    }

    public ICheckbox CreateCheckbox()
    {
        return new MacCheckbox();
    }
}

// Factory concreta para Linux
public class LinuxFactory : IUIFactory
{
    public IButton CreateButton()
    {
        return new LinuxButton();
    }

    public IWindow CreateWindow()
    {
        return new LinuxWindow();
    }

    public ICheckbox CreateCheckbox()
    {
        return new LinuxCheckbox();
    }
}
Paso 5: Cliente que usa la Factory
csharppublic class Aplicacion
{
    private IButton _button;
    private IWindow _window;
    private ICheckbox _checkbox;

    //  Cliente recibe factory, no sabe qué plataforma es
    public Aplicacion(IUIFactory factory)
    {
        _button = factory.CreateButton();
        _window = factory.CreateWindow();
        _checkbox = factory.CreateCheckbox();
    }

    public void Ejecutar()
    {
        _window.Open();
        _button.Render();
        _button.Click();
        _checkbox.Render();
        _checkbox.Check();
        _window.Maximize();
    }
}

// Uso
var platform = DetectarPlataforma(); // "Windows", "Mac", "Linux"

IUIFactory factory = platform switch
{
    "Windows" => new WindowsFactory(),
    "Mac" => new MacFactory(),
    "Linux" => new LinuxFactory(),
    _ => throw new PlatformNotSupportedException()
};

var app = new Aplicacion(factory);
app.Ejecutar();
Enter fullscreen mode Exit fullscreen mode

PARTE 7: CUÁNDO USAR ABSTRACT FACTORY
Usa Abstract Factory cuando:

Necesitas familias de objetos relacionados

UI: Botón + Ventana + Menú para cada plataforma
Temas: Colores + Fuentes + Iconos para cada tema

Los objetos deben ser compatibles entre sí

No puedes mezclar botón de Windows con ventana de Mac
Todos deben ser de la misma familia

Quieres ocultar las implementaciones concretas

Cliente solo ve interfaces
No conoce las clases concretas

Quieres cambiar toda la familia fácilmente

De tema claro a oscuro
De MySQL a PostgreSQL

Tienes múltiples variantes de múltiples productos

3 plataformas × 5 componentes = 15 clases
Necesitas organización

NO uses Abstract Factory cuando:

Solo tienes un tipo de producto

Usa Factory Method

Las familias no son compatibles entre sí

Los objetos son independientes

No hay variaciones de familias

Solo una plataforma, un tema, etc.

Agregarás nuevos productos frecuentemente

Modificarás la interfaz abstracta constantemente

PARTE 8: VENTAJAS Y DESVENTAJAS
Ventajas:

Garantiza compatibilidad

Todos los productos son de la misma familia

Aislamiento de clases concretas

Cliente usa interfaces

Fácil cambiar familias

Solo cambias el factory

Single Responsibility

Creación centralizada

Open/Closed

Nuevas familias sin modificar cliente

Desventajas:

Complejidad

Muchas interfaces y clases

Difícil agregar nuevos productos

Debes modificar la interfaz AbstractFactory
Todas las factories concretas

Rigidez

La estructura está definida desde el inicio

Overkill para casos simples

Factory Method puede ser suficiente

Top comments (0)