0Pricing
C# Academy · Lección

Patrones Factory y Options

Use delegados de factory, IServiceProvider y el patrón Options para gestionar dependencias condicionales o configurables.

Patrones Factory y Options es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

Cuando la inyección mediante constructor no es suficiente

A veces necesita crear servicios de forma condicional, según datos en tiempo de ejecución, o configurarlos de manera diferente en cada caso de uso. Ahí es donde destacan los patrones Factory y Options.

Delegados de fábrica con AddTransient

Puede pasar un delegado de fábrica a AddTransient, AddScoped o AddSingleton. El delegado recibe IServiceProvider, por lo que puede resolver otros servicios.

builder.Services.AddTransient<IPaymentGateway>(sp =>
{
    var config = sp.GetRequiredService<IOptions<PaymentConfig>>().Value;
    return config.Provider == "stripe"
        ? new StripeGateway(config.ApiKey)
        : new PayPalGateway(config.ClientId, config.Secret);
});

Opciones con nombre e IOptionsSnapshot

El patrón Options vincula secciones de configuración con clases fuertemente tipadas. Use IOptions<T> para Singletons y IOptionsSnapshot<T> para valores que se actualizan por solicitud.

public class SmtpSettings
{
    public string Host { get; set; } = "";
    public int Port { get; set; } = 587;
    public string Username { get; set; } = "";
}

// Registration
builder.Services.Configure<SmtpSettings>(
    builder.Configuration.GetSection("Smtp"));

// Consumption
public class EmailService
{
    private readonly SmtpSettings _settings;
    public EmailService(IOptions<SmtpSettings> opts)
        => _settings = opts.Value;
}

IOptionsMonitor para Hot Reload

IOptionsMonitor<T> proporciona el valor actual de una opción en el momento del acceso y le notifica cuando cambia la configuración; es perfecto para Singletons que necesitan actualizaciones de configuración en vivo.

public class FeatureFlagService
{
    private readonly IOptionsMonitor<FeatureFlags> _monitor;

    public FeatureFlagService(IOptionsMonitor<FeatureFlags> monitor)
        => _monitor = monitor;

    public bool IsEnabled(string flag)
    {
        // Always reads the latest config value
        return _monitor.CurrentValue.Flags.GetValueOrDefault(flag);
    }
}

Opciones con nombre

Las opciones con nombre permiten registrar varias configuraciones del mismo tipo. Use Configure<T>(name, ...) y resuélvalas con IOptionsSnapshot<T>.Get(name).

builder.Services.Configure<S3Settings>("primary",
    builder.Configuration.GetSection("S3:Primary"));
builder.Services.Configure<S3Settings>("backup",
    builder.Configuration.GetSection("S3:Backup"));

public class S3Service
{
    public S3Service(IOptionsSnapshot<S3Settings> opts)
    {
        var primary = opts.Get("primary");
        var backup  = opts.Get("backup");
    }
}

Validar opciones al iniciar

Use ValidateDataAnnotations() o un validador personalizado para asegurarse de que la configuración sea correcta antes de iniciar la aplicación. Combínelo con ValidateOnStart() para que la aplicación falle de inmediato ante un error.

public class SmtpSettings
{
    [Required] public string Host { get; set; } = "";
    [Range(1, 65535)] public int Port { get; set; } = 587;
}

builder.Services
    .AddOptions<SmtpSettings>()
    .Bind(builder.Configuration.GetSection("Smtp"))
    .ValidateDataAnnotations()
    .ValidateOnStart();

Patrón Abstract Factory

Una interfaz de fábrica abstracta permite inyectar una fábrica en los servicios y retrasar la construcción hasta que haya datos disponibles en tiempo de ejecución, sin depender directamente de IServiceProvider.

public interface IReportFactory
{
    IReport Create(string reportType);
}

public class ReportFactory : IReportFactory
{
    private readonly IServiceProvider _sp;
    public ReportFactory(IServiceProvider sp) => _sp = sp;

    public IReport Create(string reportType) => reportType switch
    {
        "pdf"  => _sp.GetRequiredService<PdfReport>(),
        "excel"=> _sp.GetRequiredService<ExcelReport>(),
        _      => throw new ArgumentException("Unknown type")
    };
}

builder.Services.AddTransient<IReportFactory, ReportFactory>();

Servicios con clave (.NET 8)

.NET 8 introduce los servicios con clave: registre varias implementaciones con claves diferentes y resuelva la adecuada mediante [FromKeyedServices] o GetKeyedService.

builder.Services.AddKeyedScoped<IPaymentGateway, StripeGateway>("stripe");
builder.Services.AddKeyedScoped<IPaymentGateway, PayPalGateway>("paypal");

// Resolve in a class:
public class CheckoutService(
    [FromKeyedServices("stripe")] IPaymentGateway stripe,
    [FromKeyedServices("paypal")]  IPaymentGateway paypal) { }

PostConfigure para aplicar sobrescrituras

PostConfigure se ejecuta después de todas las llamadas a Configure. Úselo para aplicar sobrescrituras en las pruebas o imponer invariantes independientemente de la configuración que se haya cargado.

// In integration tests: force test values after real config
builder.Services.PostConfigure<SmtpSettings>(opts =>
{
    opts.Host = "smtp.test.local";
    opts.Port = 25;
});

Métodos de extensión de IServiceCollection

Incluya los registros en métodos de extensión para mantener limpio Program.cs y hacer que los módulos puedan reutilizarse en distintos proyectos.

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddPaymentServices(
        this IServiceCollection services,
        IConfiguration config)
    {
        services.Configure<PaymentConfig>(config.GetSection("Payment"));
        services.AddScoped<IPaymentGateway, StripeGateway>();
        services.AddScoped<PaymentService>();
        return services;
    }
}

// Usage in Program.cs:
builder.Services.AddPaymentServices(builder.Configuration);

En la práctica: notificaciones con varios proveedores

Al combinar una fábrica y opciones con nombre, puede seleccionar el proveedor de notificaciones adecuado en tiempo de ejecución según la preferencia del usuario almacenada en la base de datos.

builder.Services.AddKeyedScoped<INotifier, EmailNotifier>("email");
builder.Services.AddKeyedScoped<INotifier, SmsNotifier>("sms");
builder.Services.AddKeyedScoped<INotifier, PushNotifier>("push");

public class NotificationService
{
    private readonly IServiceProvider _sp;
    public NotificationService(IServiceProvider sp) => _sp = sp;

    public Task SendAsync(string channel, string message)
    {
        var notifier = _sp.GetRequiredKeyedService<INotifier>(channel);
        return notifier.SendAsync(message);
    }
}

Comprobación rápida

¿Qué interfaz proporciona el valor actual de las opciones Y notifica los cambios de configuración, por lo que resulta adecuada para servicios Singleton?

Recapitulación: patrones Factory y Options

Ideas clave:

  • Los delegados de fábrica en los métodos Add* permiten crear servicios de forma condicional o configurada en tiempo de ejecución
  • El patrón Options vincula secciones de configuración con POCOs fuertemente tipados
  • IOptions = estático, IOptionsSnapshot = por solicitud, IOptionsMonitor = actualizaciones en vivo
  • Valide las opciones al iniciar con ValidateDataAnnotations().ValidateOnStart()
  • Los servicios con clave (.NET 8) sustituyen las soluciones basadas en fábricas para implementaciones con nombre

Preguntas frecuentes

¿La lección «Patrones Factory y Options» es gratis?

Sí — el texto completo de «Patrones Factory y Options» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Patrones Factory y Options»?

Use delegados de factory, IServiceProvider y el patrón Options para gestionar dependencias condicionales o configurables. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Patrones Factory y Options»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Fundamentos de los contenedores DI
  2. Ciclos de vida de servicios: Transient, Scoped, Singleton
  3. Inyección por constructor e interfaces
  4. Patrones Factory y Options
← Volver a C# Academy