CodeShot
Leadسختی 5 از ۵· در 33٪ مصاحبه‌های این حوزه پرسیده شده

چرا Service Locator یک Anti-Pattern است؟

نشان کردن

پاسخ کوتاه

چون وابستگی‌های واقعی کلاس را پنهان می‌کند؛ امضای سازنده دیگر نمی‌گوید کلاس به چه چیزهایی نیاز دارد و خطاها به زمان اجرا موکول می‌شوند.

پاسخ کامل

در Service Locator، کلاس یک Container را می‌گیرد و هر وقت لازم داشت از آن سرویس می‌خواهد. مشکل اینجاست:

  1. وابستگی‌های پنهان: با نگاه به سازنده نمی‌فهمید کلاس به چه چیزی نیاز دارد.
  2. شکست در زمان اجرا: فراموشی یک ثبت، به‌جای خطای Compile یا خطای startup، وسط یک درخواست کاربر ظاهر می‌شود.
  3. تست دشوار: برای تست باید کل Container را بسازید، نه فقط چند Fake.

استثنای مشروع: Factoryها و نقاط ورودی فریم‌ورک (مثل IServiceScopeFactory در یک Background Service) که ذاتاً باید در زمان اجرا Scope بسازند.

مثال کد

// ❌ Service Locator
public class OrderService
{
    private readonly IServiceProvider _provider;
    public OrderService(IServiceProvider provider) => _provider = provider;

    public void Process()
    {
        var repo = _provider.GetRequiredService<IOrderRepository>();
    }
}

// ✅ وابستگی صریح
public class OrderService
{
    private readonly IOrderRepository _repository;
    public OrderService(IOrderRepository repository) => _repository = repository;
}

نکته مهم

اگر سازنده یک کلاس بیش از حد شلوغ شده، راه‌حل پناه‌بردن به Service Locator نیست؛ نشانه این است که کلاس مسئولیت‌های زیادی دارد و باید شکسته شود.

اشتباه رایج

❌ توجیه Service Locator با «سازنده‌ام خیلی پارامتر داشت» — این مشکل طراحی است، نه مشکل DI.