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
- Podstawy kontenera DI
- Czas życia usług: Transient, Scoped, Singleton
- Wstrzykiwanie przez konstruktor i interfejsy
- Wzorce Factory i Options