TGViewer
Библиотека шарписта | C#, F#, .NET, ASP.NET Библиотека шарписта | C#, F#, .NET, ASP.NET @csharpproglib · 21.7K subscribers
Post #7098 2.78K
✏️ Service Locator. Почему это антипаттерн, а не альтернатива DI

Service Locator — это глобальный реестр сервисов. Любой класс в любой момент может запросить нужную зависимость через что-то вроде ServiceLocator.Get<IEmailService>(). Выглядит удобно и гибко. На практике — это ловушка, которая усложняет поддержку кода с каждым месяцем.

Марк Симанн назвал этот паттерн антипаттерном ещё в 2010 году. С тех пор аргументы стали только сильнее.

В чём проблема

Когда класс получает зависимости через конструктор, вы видите всё, что ему нужно, прямо в сигнатуре:
public class OrderService
{
private readonly IEmailService _email;
private readonly IOrderRepository _repo;

public OrderService(IEmailService email, IOrderRepository repo)
{
_email = email;
_repo = repo;
}
}


Два параметра — две зависимости. Всё на виду.

Теперь тот же класс через Service Locator:
public class OrderService
{
public void PlaceOrder(Order order)
{
var repo = ServiceLocator.Get<IOrderRepository>();
repo.Save(order);

var email = ServiceLocator.Get<IEmailService>();
email.SendConfirmation(order);
}
}


Снаружи OrderService выглядит так, будто ему ничего не нужно. Зависимости спрятаны внутри метода. Чтобы понять, что класс использует, нужно читать весь его код. На десяти классах это неудобно. На сотне — это археология.

Тесты превращаются в боль

Для юнит-теста с constructor injection вы просто передаёте моки в конструктор.

var service = new OrderService(mockEmail, mockRepo);


С Service Locator нужно сначала настроить глобальный реестр, зарегистрировать в нём все нужные моки, убедиться, что между тестами состояние очищается. Тесты становятся хрупкими и зависимыми друг от друга.

IServiceProvider в бизнес-логике — тот же Service Locator

В .NET есть встроенный DI-контейнер, и соблазн использовать IServiceProvider напрямую велик. Но если вы инжектите IServiceProvider в бизнес-класс и достаёте из него сервисы вручную, это ровно тот же Service Locator, просто в обёртке от Microsoft:
// Так делать не стоит
public class ReportGenerator
{
private readonly IServiceProvider _provider;

public ReportGenerator(IServiceProvider provider)
{
_provider = provider;
}

public void Generate()
{
var formatter = _provider.GetRequiredService<IReportFormatter>();
// ...
}
}


Зависимость от IReportFormatter снова спрятана. Конструктор говорит только «мне нужен весь контейнер», что бесполезно.

Правильный вариант:
public class ReportGenerator
{
private readonly IReportFormatter _formatter;

public ReportGenerator(IReportFormatter formatter)
{
_formatter = formatter;
}

public void Generate()
{
// _formatter уже здесь
}
}


Когда IServiceProvider допустим

Есть ограниченный список ситуаций, где обращение к IServiceProvider оправдано. Фабрики, которые создают объекты с разным временем жизни. Плагинные системы, где набор сервисов неизвестен на этапе компиляции. Инфраструктурный код фреймворка, middleware, активаторы. Во всех этих случаях речь идёт об инфраструктуре, а не о бизнес-логике.

Если ваш класс решает доменную задачу и при этом тянет IServiceProvider, стоит вынести конкретную зависимость в конструктор. Код станет прозрачнее, тесты проще, а рефакторинг перестанет быть раскопками.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#il_люминатор
  • ❤ 8
  • 👍 4
  • ❤‍🔥 2
More from @csharpproglib
  1. Sep 21, 2026⚙️ Настоящие атомарные операции Если Volatile решает проблему видимости, то Interlocked ре…
  2. Sep 20, 2026💪 Разминка перед трудовыми буднями Что произойдёт? ❤️ — список станет [1, 3] 🔥 — Invalid…
  3. Sep 19, 2026🧩 Middleware в ASP.NET Core: 3 ловушки Middleware — звено HTTP pipeline: app.Use(async (c…
  4. Sep 18, 2026📍 Навигация: Вакансии • Задачи • Собесы 🐸Библиотека шарписта #garbage_collector
  5. Sep 17, 2026🦆 Duck typing в C# — почти как в TypeScript В TypeScript достаточно, чтобы у объекта был…
  6. Sep 17, 2026🧠 Почему .NET-под съедает всю память? kubectl top pod показывает 1 ГБ, а managed heap зан…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →