Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Service Locator?
Service Locator — это паттерн проектирования, который предоставляет центральный реестр для получения экземпляров сервисов. Вместо инъекции зависимостей (Dependency Injection), класс сам запрашивает нужный сервис из локатора.
Service Locator паттерн
// Центральный реестр сервисов
public class ServiceLocator
{
private static Dictionary<Type, object> _services = new();
public static void Register<T>(T instance)
{
_services[typeof(T)] = instance;
}
public static T GetService<T>()
{
return (T)_services[typeof(T)];
}
}
// Использование
public class UserService
{
private ILogger _logger = ServiceLocator.GetService<ILogger>(); // поиск в локаторе
}
Инициализация
static void Main()
{
// Регистрируем сервисы в локаторе
ServiceLocator.Register<ILogger>(new ConsoleLogger());
ServiceLocator.Register<IUserRepository>(new UserRepository());
// Теперь классы могут получать их
var userService = new UserService();
}
Проблемы Service Locator
1. Скрытые зависимости
public class UserService
{
public UserService() // Конструктор НЕ показывает зависимости
{
_logger = ServiceLocator.GetService<ILogger>(); // спрятано внутри
}
}
// Трудно понять, что нужно сервису!
2. Сложнее тестировать
[Test]
public void TestUserService()
{
// Нужно настроить весь Service Locator перед тестом
ServiceLocator.Register<ILogger>(new MockLogger());
var service = new UserService();
service.DoSomething();
// Vs DI — просто передаешь mock в конструктор
}
3. Runtime ошибки вместо compile-time
// Service Locator — ошибка при запуске
var logger = ServiceLocator.GetService<ILogger>(); // может быть null!
// DI — ошибка при компиляции
public UserService(ILogger logger) // если забыл регистрировать — падает на старте
{
_logger = logger;
}
Правильный подход — Dependency Injection
// ✅ DI: зависимости в конструкторе
public class UserService
{
private readonly ILogger _logger;
private readonly IUserRepository _repo;
public UserService(ILogger logger, IUserRepository repo) // явные зависимости
{
_logger = logger;
_repo = repo;
}
}
// Регистрация в контейнере
var services = new ServiceCollection();
services.AddScoped<ILogger, ConsoleLogger>();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<UserService>();
var serviceProvider = services.BuildServiceProvider();
var userService = serviceProvider.GetRequiredService<UserService>();
Когда Service Locator может быть полезен
- Legacy код — если нельзя переделать на DI
- Factory паттерн — когда не знаешь тип на время компиляции
- Плагины — динамическая загрузка модулей
// Factory с Service Locator
public class PaymentProviderFactory
{
public IPaymentProvider CreateProvider(string type)
{
// Динамически получаем нужный провайдер
var providerType = Type.GetType($"Company.Payment.{type}Provider");
return ServiceLocator.GetService(providerType) as IPaymentProvider;
}
}
Service Locator vs Dependency Injection
| Аспект | Service Locator | Dependency Injection |
|---|---|---|
| Видимость зависимостей | Скрыта | Явная (конструктор) |
| Тестирование | Сложнее | Проще (передаешь моки) |
| Type Safety | Runtime | Compile-time |
| Сложность | Меньше | Больше |
| Масштабируемость | Плохо | Хорошо |
ASP.NET Core — встроенный DI контейнер
public class Startup
{
public void ConfigureServices(IServiceCollection services) // регистрация
{
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<UserService>();
}
}
public class UserController : ControllerBase
{
private readonly UserService _service; // инъекция через конструктор
public UserController(UserService service)
{
_service = service; // ASP.NET автоматически создал и передал
}
}
Итог
Service Locator — это анти-паттерн в современном .NET. Используй Dependency Injection (встроенный контейнер в ASP.NET Core) — это лучше для тестирования, масштабируемости и читаемости кода.