0Pricing
C# Academy · Lekcja

Wzorce Factory i Options

Używaj delegatów fabrykujących, IServiceProvider i wzorca Options do obsługi zależności warunkowych lub konfigurowalnych.

Wzorce Factory i Options to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Gdy wstrzykiwanie przez konstruktor nie wystarcza

Czasami trzeba tworzyć usługi warunkowo, na podstawie danych dostępnych w czasie działania, albo konfigurować je inaczej dla poszczególnych przypadków użycia. W takich sytuacjach przydatne są wzorce fabryki i Options.

Delegaty fabrykujące z AddTransient

Do metod AddTransient, AddScoped lub AddSingleton można przekazać delegat fabrykujący. Delegat otrzymuje IServiceProvider, dzięki czemu może rozwiązywać inne usługi.

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);
});

Nazwane opcje z IOptionsSnapshot

Wzorzec Options wiąże sekcje konfiguracji z klasami o silnym typowaniu. Należy używać IOptions<T> dla singletonów oraz IOptionsSnapshot<T> dla wartości odświeżanych przy każdym żądaniu.

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 do przeładowywania konfiguracji

IOptionsMonitor<T> udostępnia bieżącą wartość opcji w momencie odczytu i powiadamia o zmianach konfiguracji — jest idealny dla singletonów, które wymagają aktualizacji konfiguracji w czasie działania.

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);
    }
}

Nazwane opcje

Nazwane opcje pozwalają zarejestrować wiele konfiguracji tego samego typu. Należy użyć Configure<T>(name, ...), a następnie rozwiązać konfigurację za pomocą 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");
    }
}

Walidowanie opcji podczas uruchamiania

Należy użyć ValidateDataAnnotations() lub niestandardowego walidatora, aby upewnić się, że konfiguracja jest poprawna przed uruchomieniem aplikacji. W połączeniu z ValidateOnStart() zapewnia to szybkie zgłaszanie błędów.

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();

Wzorzec fabryki abstrakcyjnej

Interfejs fabryki abstrakcyjnej umożliwia wstrzyknięcie fabryki do usług i odłożenie tworzenia obiektów do czasu, gdy dostępne będą dane z czasu działania — bez bezpośredniej zależności od 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>();

Usługi kluczowane (.NET 8)

.NET 8 wprowadza usługi kluczowane: można rejestrować wiele implementacji pod różnymi kluczami, a następnie rozwiązywać właściwą za pomocą [FromKeyedServices] lub 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 do nadpisywania ustawień

PostConfigure jest wykonywane po wszystkich wywołaniach Configure. Należy go używać do stosowania nadpisań w testach lub wymuszania niezmienników niezależnie od tego, jaka konfiguracja została wczytana.

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

Metody rozszerzające IServiceCollection

Rejestracje można umieścić w metodach rozszerzających, aby zachować przejrzystość pliku Program.cs i umożliwić ponowne używanie modułów w różnych projektach.

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);

W praktyce: powiadomienia od wielu dostawców

Łącząc fabrykę z nazwanymi opcjami, można w czasie działania wybrać właściwego dostawcę powiadomień na podstawie preferencji użytkownika zapisanej w bazie danych.

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);
    }
}

Szybkie sprawdzenie

Który interfejs udostępnia bieżącą wartość opcji i powiadamia o zmianach konfiguracji, dzięki czemu nadaje się do usług Singleton?

Podsumowanie: wzorce fabryki i Options

Najważniejsze informacje:

  • Delegaty fabrykujące w metodach Add* umożliwiają warunkowe tworzenie usług lub tworzenie ich na podstawie konfiguracji z czasu działania
  • Wzorzec Options wiąże sekcje konfiguracji z silnie typowanymi obiektami POCO
  • IOptions = wartości statyczne, IOptionsSnapshot = wartości odświeżane dla każdego żądania, IOptionsMonitor = aktualizacje na żywo
  • Opcje należy walidować podczas uruchamiania za pomocą ValidateDataAnnotations().ValidateOnStart()
  • Usługi kluczowane (.NET 8) zastępują obejścia oparte na fabrykach w przypadku nazwanych implementacji

Często zadawane pytania

Czy lekcja „Wzorce Factory i Options” jest bezpłatna?

Tak — pełny tekst „Wzorce Factory i Options” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Wzorce Factory i Options”?

Używaj delegatów fabrykujących, IServiceProvider i wzorca Options do obsługi zależności warunkowych lub konfigurowalnych. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Wzorce Factory i Options”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy kontenera DI
  2. Czas życia usług: Transient, Scoped, Singleton
  3. Wstrzykiwanie przez konstruktor i interfejsy
  4. Wzorce Factory i Options
← Powrót do C# Academy