A modern szoftverfejlesztés egyik legnagyobb kihívása a loosely coupled, könnyen tesztelhető és karbantartható kód írása. Amikor komplex alkalmazásokat építünk, gyakran találkozunk azzal a problémával, hogy az osztályaink szorosan összefüggenek egymással, ami megnehezíti a módosításokat és a hibakeresést. Ez a jelenség különösen akkor válik problémává, amikor egy osztály közvetlenül példányosítja a függőségeit, ezáltal merev kapcsolatot teremtve közöttük.
A dependency injection (függőséginjektálás) egy olyan tervezési minta, amely lehetővé teszi, hogy az objektumok ne maguk hozzák létre a függőségeiket, hanem külső forrásból kapják meg azokat. Ez a megközelítés forradalmasította az objektumorientált programozást, mivel jelentősen javítja a kód modularitását, tesztelhetőségét és újrafelhasználhatóságát. A pattern különböző implementációs módokat kínál, és számos programozási nyelvben elérhető.
Ez az útmutató átfogó képet nyújt a dependency injection működéséről, típusairól és gyakorlati alkalmazásáról. Megismerheted a legfontosabb DI containereket, megtanulhatod, hogyan implementálhatod saját projektjeidben, és választ kapsz a leggyakoribb kérdésekre is. Emellett konkrét kódpéldákon keresztül láthatod, hogyan változtatja meg ez a pattern a fejlesztési folyamatot.
Mi a dependency injection és miért fontos?
A dependency injection alapvetően arról szól, hogy az objektumok függőségeit nem belülről hozzák létre, hanem külső forrásból kapják meg. Ez a megközelítés megfordítja a hagyományos objektumkészítési logikát.
Hagyományos megközelítésben egy EmailService osztály közvetlenül példányosítaná a DatabaseConnection objektumot. Ez szoros kapcsolatot teremt a két osztály között, ami problémás lehet teszteléskor vagy amikor más adatbázis-kapcsolatot szeretnénk használni.
A dependency injection alkalmazásával az EmailService konstruktorán vagy property-jén keresztül kapja meg a szükséges DatabaseConnection objektumot. Ez lehetővé teszi, hogy különböző implementációkat használjunk anélkül, hogy módosítanánk az EmailService kódját.
A dependency injection típusai és megvalósítási módjai
Constructor Injection
A constructor injection a leggyakrabban használt forma, ahol a függőségeket az objektum konstruktorán keresztül adjuk át. Ez biztosítja, hogy az objektum mindig teljes állapotban jöjjön létre.
public class OrderService
{
private readonly IPaymentProcessor _paymentProcessor;
private readonly IEmailService _emailService;
public OrderService(IPaymentProcessor paymentProcessor, IEmailService emailService)
{
_paymentProcessor = paymentProcessor;
_emailService = emailService;
}
}
Ez a megközelítés garantálja, hogy a szükséges függőségek rendelkezésre álljanak az objektum teljes életciklusa során. A readonly mezők használata további biztonságot nyújt.
Property Injection
A property injection esetén a függőségeket az objektum property-jein keresztül állítjuk be. Ez rugalmasabb, de kevésbé biztonságos megoldás.
public class UserService
{
public IUserRepository UserRepository { get; set; }
public ILogger Logger { get; set; }
public void CreateUser(User user)
{
UserRepository?.Save(user);
Logger?.Log("User created");
}
}
Method Injection
A method injection során a függőségeket közvetlenül a metódusoknak adjuk át paraméterként. Ez akkor hasznos, amikor csak bizonyos műveletek igénylik az adott függőséget.
DI Containerek és IoC keretrendszerek
Népszerű .NET DI Containerek
A .NET ökoszisztémában számos dependency injection container áll rendelkezésre, amelyek különböző funkciókkal és teljesítményjellemzőkkel rendelkeznek.
| Container | Teljesítmény | Funkciók | Tanulási görbe |
|---|---|---|---|
| Microsoft.Extensions.DependencyInjection | Közepes | Alapvető | Alacsony |
| Autofac | Jó | Gazdag | Közepes |
| Ninject | Alacsony | Gazdag | Magas |
| Castle Windsor | Jó | Gazdag | Magas |
A Microsoft.Extensions.DependencyInjection az ASP.NET Core beépített containere. Egyszerű használat jellemzi, és a legtöbb alapvető igényt kielégíti. Az Autofac összetettebb forgatókönyvekhez nyújt megoldást, míg a Ninject kifejezetten a könnyű konfigurálhatóságra fókuszál.
Java DI Frameworks
A Java világában a Spring Framework dominál a dependency injection területén. A Spring IoC container rendkívül fejlett funkciókat kínál, beleértve az XML és annotation-alapú konfigurációt.
@Component
public class BookService {
@Autowired
private BookRepository bookRepository;
@Autowired
private EmailService emailService;
}
A Google Guice egy könnyebb alternatíva, amely compile-time ellenőrzést biztosít. A CDI (Contexts and Dependency Injection) pedig a Java EE szabvány része.
Lifetime Management és Scope kezelés
Singleton Pattern vs DI Singleton
A hagyományos singleton pattern és a DI container által kezelt singleton között lényeges különbségek vannak. A DI singleton thread-safe módon kezeli az objektum életciklusát.
services.AddSingleton<IConfigurationService, ConfigurationService>();
services.AddScoped<IUserService, UserService>();
services.AddTransient<IEmailSender, EmailSender>();
A Singleton scope esetén egyetlen példány jön létre az alkalmazás teljes futási ideje alatt. A Scoped objektumok HTTP kérésenként vagy tranzakciónként jönnek létre. A Transient objektumok minden alkalommal új példányként kerülnek létrehozásra.
Memory Management és Performance
A helyes lifetime management kritikus a memóriahasználat és a teljesítmény szempontjából. A hosszú életciklusú objektumok referenciákat tarthatnak rövid életciklusú objektumokra, ami memory leak-hez vezethet.
"A dependency injection helyes használata jelentősen javítja az alkalmazás teljesítményét és stabilitását, de helytelen implementáció esetén komoly problémákat okozhat."
Tesztelhetőség és Mock objektumok
Unit Testing előnyei
A dependency injection egyik legnagyobb előnye a könnyű tesztelhetőség. Mock objektumok használatával izoláltan tesztelhetjük az egyes komponenseket.
[Test]
public void CreateOrder_ShouldProcessPayment()
{
// Arrange
var mockPaymentProcessor = new Mock<IPaymentProcessor>();
var mockEmailService = new Mock<IEmailService>();
var orderService = new OrderService(mockPaymentProcessor.Object, mockEmailService.Object);
// Act
orderService.CreateOrder(new Order());
// Assert
mockPaymentProcessor.Verify(x => x.ProcessPayment(It.IsAny<decimal>()), Times.Once);
}
Ez a megközelítés lehetővé teszi, hogy a tesztek gyorsak és megbízhatóak legyenek, mivel nem függnek külső erőforrásoktól.
Integration Testing stratégiák
Az integrációs teszteknél a valódi implementációkat használjuk, de kontrollált környezetben. A DI container segít abban, hogy könnyedén válthassunk a test és production konfigurációk között.
SOLID principiumok és DI kapcsolata
Dependency Inversion Principle
A Dependency Inversion Principle (DIP) kimondja, hogy a magas szintű modulok ne függjenek alacsony szintű moduloktól. Mindkettő absztrakcióktól függjön.
A dependency injection ezt a principiumot valósítja meg gyakorlatban. Az osztályok interfészektől függenek, nem konkrét implementációktól, így könnyen cserélhetők és tesztelhetők.
Open/Closed Principle támogatása
Az Open/Closed Principle szerint az osztályoknak nyitottnak kell lenniük a kiterjesztésre, de zártnak a módosításra. A DI ezt úgy támogatja, hogy új implementációkat adhatunk hozzá anélkül, hogy módosítanánk a meglévő kódot.
"A SOLID principiumok és a dependency injection együttes alkalmazása robusztus és karbantartható szoftverarchitektúra alapját képezi."
Anti-patterns és gyakori hibák
Service Locator Anti-pattern
A Service Locator pattern gyakran tévesen dependency injection-ként kerül implementálásra. Ez azonban anti-pattern, mert rejtett függőségeket hoz létre.
// Anti-pattern - Service Locator
public class OrderService
{
public void ProcessOrder(Order order)
{
var paymentService = ServiceLocator.GetService<IPaymentService>();
var emailService = ServiceLocator.GetService<IEmailService>();
}
}
Ez a megközelítés megnehezíti a tesztelést és elrejti a valódi függőségeket.
Constructor Over-injection
Amikor egy konstruktor túl sok paramétert kap, az gyakran azt jelzi, hogy az osztály túl sok felelősséggel rendelkezik. Ez a Single Responsibility Principle megsértését jelenti.
// Problémás - túl sok függőség
public class UserService
{
public UserService(
IUserRepository userRepo,
IEmailService emailService,
ILogger logger,
IValidationService validator,
ICacheService cache,
IEventPublisher eventPublisher,
ISecurityService security,
IAuditService audit)
{
// túl sok felelősség
}
}
Circular Dependencies
A körkörös függőségek komoly problémát jelentenek a DI containerek számára. A helyes tervezéssel elkerülhetők ezek a helyzetek.
"A körkörös függőségek általában rossz architektúrális döntések eredményei, amelyeket újratervezéssel kell megoldani."
Framework-specifikus implementációk
ASP.NET Core DI
Az ASP.NET Core beépített dependency injection rendszere egyszerű és hatékony. A Startup.cs fájlban konfiguráljuk a szolgáltatásokat.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IUserService, UserService>();
services.AddSingleton<IConfigurationService, ConfigurationService>();
services.AddTransient<IEmailSender, SmtpEmailSender>();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
}
A controller osztályokban automatikusan injektálódnak a függőségek.
Spring Framework
A Spring Framework komplex konfigurációs lehetőségeket biztosít. Az @Autowired annotáció automatikusan injektálja a függőségeket.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private EmailService emailService;
@Qualifier("primaryEmailService")
@Autowired
private EmailService primaryEmailService;
}
A @Qualifier annotáció segít megkülönböztetni az azonos típusú implementációkat.
Performance optimalizálás és best practices
Lazy Loading és Deferred Execution
A lazy loading segít optimalizálni az alkalmazás indítási idejét azáltal, hogy csak akkor hozza létre az objektumokat, amikor ténylegesen szükség van rájuk.
public class ExpensiveService
{
private readonly Lazy<IHeavyDependency> _heavyDependency;
public ExpensiveService(Lazy<IHeavyDependency> heavyDependency)
{
_heavyDependency = heavyDependency;
}
public void DoWork()
{
if (someCondition)
{
_heavyDependency.Value.PerformHeavyOperation();
}
}
}
Factory Pattern integráció
A Factory pattern kombinálása a dependency injection-nel rugalmas objektum-létrehozási mechanizmust biztosít.
public interface IEmailServiceFactory
{
IEmailService CreateEmailService(EmailType type);
}
public class EmailServiceFactory : IEmailServiceFactory
{
private readonly IServiceProvider _serviceProvider;
public EmailServiceFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IEmailService CreateEmailService(EmailType type)
{
return type switch
{
EmailType.Smtp => _serviceProvider.GetService<SmtpEmailService>(),
EmailType.SendGrid => _serviceProvider.GetService<SendGridEmailService>(),
_ => throw new ArgumentException("Unknown email type")
};
}
}
Microservices architektúrában való alkalmazás
Service Discovery és DI
Microservices környezetben a dependency injection kiterjed a szolgáltatások közötti kommunikációra is. A service discovery mechanizmusok integrálódnak a DI containerekkel.
| Megközelítés | Előnyök | Hátrányok | Használati terület |
|---|---|---|---|
| Client-side Discovery | Egyszerű implementáció | Tight coupling | Kis rendszerek |
| Server-side Discovery | Loose coupling | Komplexebb infrastruktúra | Nagy rendszerek |
| Service Mesh | Teljes körű megoldás | Magas komplexitás | Enterprise környezet |
A Consul, Eureka és Kubernetes szolgáltatásai mind támogatják a dinamikus service discovery-t.
Configuration Management
A mikroszolgáltatások konfigurációja gyakran külső forrásokból származik. A dependency injection segít abban, hogy ezeket a konfigurációkat könnyen injektáljuk.
public class ApiService
{
private readonly HttpClient _httpClient;
private readonly ApiConfiguration _config;
public ApiService(HttpClient httpClient, IOptions<ApiConfiguration> config)
{
_httpClient = httpClient;
_config = config.Value;
}
}
"A mikroszolgáltatások architektúrájában a dependency injection nem csak az objektumok közötti, hanem a szolgáltatások közötti függőségek kezelésére is kiterjed."
Debugging és troubleshooting
Container diagnosztika
A DI containerek gyakran nyújtanak diagnosztikai eszközöket a regisztrált szolgáltatások és azok életciklusának nyomon követésére.
public void LogRegisteredServices(IServiceCollection services)
{
foreach (var service in services)
{
Console.WriteLine($"Service: {service.ServiceType.Name}");
Console.WriteLine($"Implementation: {service.ImplementationType?.Name}");
Console.WriteLine($"Lifetime: {service.Lifetime}");
}
}
A logging és monitoring kritikus fontosságú a DI-alapú alkalmazások hibakeresésében.
Runtime dependency resolution
A futásidejű függőség feloldás nyomon követése segít megérteni az objektum-létrehozási folyamatot és azonosítani a teljesítménybeli szűk keresztmetszeteket.
Advanced technikák és patterns
Decorator Pattern DI-vel
A Decorator pattern kombinálása dependency injection-nel elegáns módot biztosít a cross-cutting concern-ök kezelésére.
public class CachedUserService : IUserService
{
private readonly IUserService _innerService;
private readonly ICacheService _cache;
public CachedUserService(IUserService innerService, ICacheService cache)
{
_innerService = innerService;
_cache = cache;
}
public User GetUser(int id)
{
var cacheKey = $"user_{id}";
if (_cache.TryGet(cacheKey, out User cachedUser))
{
return cachedUser;
}
var user = _innerService.GetUser(id);
_cache.Set(cacheKey, user);
return user;
}
}
Ez a megközelítés lehetővé teszi a funkcionalitás rétegzését anélkül, hogy módosítanánk az eredeti implementációt.
Generic Constraints és DI
A generic constraints használata a dependency injection-nel típusbiztos és rugalmas megoldásokat eredményez.
public interface IRepository<T> where T : class, IEntity
{
T GetById(int id);
void Save(T entity);
}
public class GenericService<T> where T : class, IEntity
{
private readonly IRepository<T> _repository;
public GenericService(IRepository<T> repository)
{
_repository = repository;
}
}
"A generic constraints és a dependency injection kombinációja erőteljes és típusbiztos megoldásokat tesz lehetővé összetett domain modellek kezelésére."
Real-world példák és case studies
E-commerce alkalmazás architektúra
Egy komplex e-commerce rendszerben a dependency injection központi szerepet játszik a különböző szolgáltatások integrációjában.
public class OrderProcessingService
{
private readonly IPaymentService _paymentService;
private readonly IInventoryService _inventoryService;
private readonly IShippingService _shippingService;
private readonly IEmailService _emailService;
private readonly ILogger<OrderProcessingService> _logger;
public OrderProcessingService(
IPaymentService paymentService,
IInventoryService inventoryService,
IShippingService shippingService,
IEmailService emailService,
ILogger<OrderProcessingService> logger)
{
_paymentService = paymentService;
_inventoryService = inventoryService;
_shippingService = shippingService;
_emailService = emailService;
_logger = logger;
}
public async Task<OrderResult> ProcessOrderAsync(Order order)
{
try
{
await _inventoryService.ReserveItemsAsync(order.Items);
var paymentResult = await _paymentService.ProcessPaymentAsync(order.Payment);
if (paymentResult.IsSuccessful)
{
await _shippingService.CreateShipmentAsync(order);
await _emailService.SendOrderConfirmationAsync(order);
_logger.LogInformation($"Order {order.Id} processed successfully");
return OrderResult.Success(order.Id);
}
await _inventoryService.ReleaseReservedItemsAsync(order.Items);
return OrderResult.Failed("Payment processing failed");
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error processing order {order.Id}");
throw;
}
}
}
Ez a példa bemutatja, hogyan koordinálhatunk összetett üzleti folyamatokat dependency injection segítségével.
Banking rendszer implementáció
A pénzügyi szektorban a biztonság és a megbízhatóság kritikus. A dependency injection segít ezeknek a követelményeknek a teljesítésében.
public class TransactionService
{
private readonly IAccountRepository _accountRepository;
private readonly ITransactionValidator _validator;
private readonly IAuditService _auditService;
private readonly IFraudDetectionService _fraudDetection;
public async Task<TransactionResult> TransferAsync(
string fromAccount,
string toAccount,
decimal amount)
{
var validationResult = await _validator.ValidateTransactionAsync(
fromAccount, toAccount, amount);
if (!validationResult.IsValid)
{
await _auditService.LogFailedTransactionAsync(
fromAccount, toAccount, amount, validationResult.Reason);
return TransactionResult.Failed(validationResult.Reason);
}
var fraudCheck = await _fraudDetection.AnalyzeTransactionAsync(
fromAccount, toAccount, amount);
if (fraudCheck.IsSuspicious)
{
await _auditService.LogSuspiciousActivityAsync(fraudCheck);
return TransactionResult.Blocked("Transaction flagged for review");
}
// Tranzakció végrehajtása
return await ExecuteTransactionAsync(fromAccount, toAccount, amount);
}
}
"A pénzügyi rendszerekben a dependency injection lehetővé teszi a különböző biztonsági és compliance rétegek könnyű integrálását és tesztelését."
Jövőbeli trendek és fejlődési irányok
Cloud-native alkalmazások
A cloud-native fejlesztésben a dependency injection új dimenziókat nyer. A serverless architektúrák és a container orchestration platformok új kihívásokat és lehetőségeket teremtenek.
A Function-as-a-Service (FaaS) platformokon a dependency injection-nek optimalizálnia kell a cold start időket. A Kubernetes környezetben a service mesh technológiák, mint az Istio vagy Linkerd, kiterjesztik a DI konceptusokat a hálózati szintre.
Reactive Programming integráció
A reaktív programozási paradigmák, mint az RxJava vagy Reactive Extensions, új megközelítéseket igényelnek a dependency injection területén.
public class ReactiveDataService
{
private readonly IObservable<DatabaseConnection> _connectionStream;
private readonly IObservable<ConfigurationChange> _configStream;
public ReactiveDataService(
IObservable<DatabaseConnection> connectionStream,
IObservable<ConfigurationChange> configStream)
{
_connectionStream = connectionStream;
_configStream = configStream;
}
public IObservable<Data> GetDataStream()
{
return _connectionStream
.CombineLatest(_configStream)
.SelectMany(tuple => FetchDataAsync(tuple.First, tuple.Second));
}
}
AI és Machine Learning integráció
A mesterséges intelligencia és gépi tanulás területén a dependency injection segít a modellek és adatforrások dinamikus cseréjében.
public class MLPredictionService
{
private readonly IModelProvider _modelProvider;
private readonly IFeatureExtractor _featureExtractor;
private readonly IDataPreprocessor _preprocessor;
public async Task<PredictionResult> PredictAsync<T>(T input)
{
var model = await _modelProvider.GetModelAsync<T>();
var features = await _featureExtractor.ExtractFeaturesAsync(input);
var processedFeatures = await _preprocessor.PreprocessAsync(features);
return await model.PredictAsync(processedFeatures);
}
}
"A jövő dependency injection rendszerei intelligens, önkonfiguráló és adaptív megoldások lesznek, amelyek képesek a futásidejű optimalizálásra és automatikus hibaelhárításra."
Platform-specifikus megfontolások
Mobile Development
A mobil alkalmazások fejlesztésében a dependency injection különleges kihívásokat jelent a korlátozott erőforrások és a platform-specifikus életciklus miatt.
Az Android platformon a Dagger és Hilt keretrendszerek compile-time dependency injection-t biztosítanak, ami jobb teljesítményt eredményez. Az iOS fejlesztésben a Swinject Swift library nyújt hasonló funkcionalitást.
Desktop alkalmazások
A desktop alkalmazásokban, különösen a WPF és WinUI környezetekben, a dependency injection integrálódik a MVVM pattern-nel.
public class MainViewModel : ViewModelBase
{
private readonly IUserService _userService;
private readonly INavigationService _navigationService;
public MainViewModel(IUserService userService, INavigationService navigationService)
{
_userService = userService;
_navigationService = navigationService;
}
}
A Prism és MVVM Light keretrendszerek beépített DI támogatást nyújtanak.
Teljesítmény monitoring és optimalizálás
Metrics és telemetria
A dependency injection rendszerek teljesítményének mérése kritikus a production környezetben való sikeres működéshez.
public class InstrumentedContainer : IServiceContainer
{
private readonly IServiceContainer _innerContainer;
private readonly IMetricsCollector _metrics;
public T Resolve<T>()
{
var stopwatch = Stopwatch.StartNew();
try
{
var result = _innerContainer.Resolve<T>();
_metrics.RecordResolutionTime(typeof(T), stopwatch.Elapsed);
return result;
}
catch (Exception ex)
{
_metrics.RecordResolutionError(typeof(T), ex);
throw;
}
}
}
A teljesítmény metrikák segítenek azonosítani a lassú objektum-létrehozási folyamatokat és optimalizálási lehetőségeket.
Memory profiling
A memóriahasználat nyomon követése különösen fontos a hosszú futású alkalmazásokban, ahol a helytelen lifetime management memory leak-eket okozhat.
Az Application Insights, New Relic és hasonló monitoring eszközök integrálhatók a DI containerekkel a részletes teljesítmény-elemzéshez.
Mik a dependency injection fő előnyei?
A dependency injection fő előnyei közé tartozik a loosely coupled architektúra kialakítása, amely javítja a kód modularitását és újrafelhasználhatóságát. A tesztelhetőség jelentősen javul, mivel mock objektumokat könnyedén injektálhatunk. A kód karbantarthatósága nő, mivel a függőségek központilag kezelhetők. Az alkalmazás rugalmassága növekszik, mivel futásidőben cserélhetjük az implementációkat anélkül, hogy módosítanánk a kliens kódot.
Milyen típusú dependency injection módszerek léteznek?
Három fő típusa van a dependency injection-nek: Constructor Injection, ahol a függőségeket a konstruktoron keresztül adjuk át; Property Injection, ahol setter metódusokat vagy property-ket használunk; és Method Injection, ahol közvetlenül a metódus paramétereiben adjuk át a függőségeket. A Constructor Injection a legbiztonságosabb, mivel garantálja a függőségek meglétét, míg a Property Injection rugalmasabb, de kevésbé biztonságos megoldás.
Hogyan választjuk ki a megfelelő DI container-t?
A megfelelő DI container kiválasztása több tényezőtől függ: a teljesítményigényektől, a szükséges funkciók komplexitásától, a tanulási görbétől és a közösségi támogatástól. Egyszerű alkalmazásokhoz a Microsoft.Extensions.DependencyInjection elegendő, míg összetett enterprise alkalmazásokhoz az Autofac vagy Castle Windsor ajánlott. Fontos figyelembe venni a dokumentáció minőségét és a hosszú távú támogatást is.
Mikor nem ajánlott a dependency injection használata?
A dependency injection nem minden esetben ajánlott. Egyszerű alkalmazások esetén túlkomplexitást okozhat, ahol a hagyományos objektum-létrehozás elegendő. Performance-kritikus alkalmazásokban a DI container overhead problémát jelenthet. Statikus utility osztályok esetén felesleges, és amikor a függőségek nagyon stabilak és ritkán változnak. Kis csapatoknál vagy prototípus fejlesztésnél a gyors fejlesztés fontosabb lehet, mint az architektúrális tisztaság.
Hogyan kerülhetjük el a circular dependency problémákat?
A circular dependency problémák elkerüléséhez több stratégia alkalmazható: Interface segregation alkalmazása, ahol kisebb, specifikus interfészeket hozunk létre; Mediator pattern használata a direkt függőségek megszüntetésére; Event-driven architektúra kialakítása; és a dependency hierarchy átgondolt tervezése. Fontos a kód review során figyelni ezekre a problémákra, és a DI container konfigurációjának validálása startup időben segít korai felismerésben.
Mi a különbség a Service Locator és a Dependency Injection között?
A Service Locator és a Dependency Injection közötti fő különbség, hogy a Service Locator esetén az objektum maga kéri el a függőségeit egy központi registry-ből, míg DI esetén a függőségek kívülről kerülnek injektálásra. A Service Locator anti-pattern, mert rejtett függőségeket hoz létre, megnehezíti a tesztelést és sérti a Hollywood Principle-t ("Don't call us, we'll call you"). A DI explicit függőségeket teremt, könnyebb tesztelést tesz lehetővé és jobb separation of concerns-t biztosít.
