Išsamus priklausomybių injekcijos (DI) ir valdymo inversijos (IoC) principų vadovas. Sužinokite, kaip kurti prižiūrimas, testuojamas ir keičiamo dydžio programas.
Priklausomybių injekcija: valdymo inversijos įvaldymas tvirtoms programoms
Programinės įrangos kūrimo srityje tvirtų, prižiūrimų ir keičiamo dydžio programų kūrimas yra svarbiausias dalykas. Priklausomybių injekcija (DI) ir valdymo inversija (IoC) yra esminiai projektavimo principai, kurie suteikia galimybę kūrėjams pasiekti šiuos tikslus. Šis išsamus vadovas nagrinėja DI ir IoC koncepcijas, pateikdamas praktinių pavyzdžių ir naudingų įžvalgų, kurios padės jums įvaldyti šias esmines technikas.
Valdymo inversijos (IoC) supratimas
Valdymo inversija (IoC) yra projektavimo principas, kai programos valdymo srautas yra apverčiamas, palyginti su tradiciniu programavimu. Užuot objektams kuriant ir valdant savo priklausomybes, ši atsakomybė perduodama išoriniam subjektui, paprastai IoC konteineriui ar sistemai. Ši valdymo inversija suteikia keletą privalumų, įskaitant:
- Sumažintas susiejimas: Objektai yra mažiau glaudžiai susieti, nes jiems nereikia žinoti, kaip sukurti ar rasti savo priklausomybes.
- Padidintas testuojamumas: Priklausomybes galima lengvai pakeisti imitacinėmis (mock) arba fiktyviomis (stub) versijomis vienetų testavimui.
- Pagerintas prižiūrimumas: Priklausomybių pakeitimai nereikalauja modifikuoti nuo jų priklausančių objektų.
- Pagerintas pakartotinis panaudojamumas: Objektus galima lengvai pakartotinai naudoti skirtinguose kontekstuose su skirtingomis priklausomybėmis.
Tradicinis valdymo srautas
Tradiciniame programavime klasė paprastai tiesiogiai sukuria savo priklausomybes. Pavyzdžiui:
class ProductService {
private $database;
public function __construct() {
$this->database = new DatabaseConnection("localhost", "username", "password");
}
public function getProduct(int $id) {
return $this->database->query("SELECT * FROM products WHERE id = " . $id);
}
}
Šis požiūris sukuria glaudų susiejimą tarp ProductService
ir DatabaseConnection
. Klasė ProductService
yra atsakinga už DatabaseConnection
kūrimą ir valdymą, todėl ją sunku testuoti ir pakartotinai naudoti.
Apverstas valdymo srautas su IoC
Naudojant IoC, ProductService
gauna DatabaseConnection
kaip priklausomybę:
class ProductService {
private $database;
public function __construct(DatabaseConnection $database) {
$this->database = $database;
}
public function getProduct(int $id) {
return $this->database->query("SELECT * FROM products WHERE id = " . $id);
}
}
Dabar ProductService
pati nekuria DatabaseConnection
. Ji pasikliauja išoriniu subjektu, kuris pateikia priklausomybę. Ši valdymo inversija padaro ProductService
lankstesne ir lengviau testuojama.
Priklausomybių injekcija (DI): IoC įgyvendinimas
Priklausomybių injekcija (DI) yra projektavimo šablonas, kuris įgyvendina valdymo inversijos principą. Jis apima objekto priklausomybių pateikimą objektui, užuot objektui pačiam jas kuriant ar ieškant. Yra trys pagrindiniai priklausomybių injekcijos tipai:
- Konstruktoriaus injekcija: Priklausomybės pateikiamos per klasės konstruktorių.
- Nustatymo metodo (Setter) injekcija: Priklausomybės pateikiamos per klasės nustatymo metodus.
- Sąsajos injekcija: Priklausomybės pateikiamos per sąsają, kurią įgyvendina klasė.
Konstruktoriaus injekcija
Konstruktoriaus injekcija yra labiausiai paplitęs ir rekomenduojamas DI tipas. Ji užtikrina, kad objektas gauna visas reikiamas priklausomybes kūrimo metu.
class UserService {
private $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function getUser(int $id) {
return $this->userRepository->find($id);
}
}
// Pavyzdinis naudojimas:
$userRepository = new UserRepository(new DatabaseConnection());
$userService = new UserService($userRepository);
$user = $userService->getUser(123);
Šiame pavyzdyje UserService
gauna UserRepository
egzempliorių per savo konstruktorių. Tai leidžia lengvai testuoti UserService
pateikiant imitacinę UserRepository
.
Nustatymo metodo (Setter) injekcija
Nustatymo metodo injekcija leidžia priklausomybes įšvirkšti po to, kai objektas jau buvo sukurtas.
class OrderService {
private $paymentGateway;
public function setPaymentGateway(PaymentGateway $paymentGateway) {
$this->paymentGateway = $paymentGateway;
}
public function processOrder(Order $order) {
$this->paymentGateway->processPayment($order->getTotal());
// ...
}
}
// Pavyzdinis naudojimas:
$orderService = new OrderService();
$orderService->setPaymentGateway(new PayPalGateway());
$orderService->processOrder($order);
Nustatymo metodo injekcija gali būti naudinga, kai priklausomybė yra neprivaloma arba gali būti pakeista vykdymo metu. Tačiau tai taip pat gali padaryti objekto priklausomybes mažiau aiškias.
Sąsajos injekcija
Sąsajos injekcija apima sąsajos apibrėžimą, kuri nurodo priklausomybės injekcijos metodą.
interface Injectable {
public function setDependency(Dependency $dependency);
}
class ReportGenerator implements Injectable {
private $dataSource;
public function setDependency(Dependency $dataSource) {
$this->dataSource = $dataSource;
}
public function generateReport() {
// Naudoti $this->dataSource ataskaitai generuoti
}
}
// Pavyzdinis naudojimas:
$reportGenerator = new ReportGenerator();
$reportGenerator->setDependency(new MySQLDataSource());
$reportGenerator->generateReport();
Sąsajos injekcija gali būti naudinga, kai norite priverstinai laikytis konkrečios priklausomybių injekcijos sutarties. Tačiau tai taip pat gali pridėti kodo sudėtingumo.
IoC konteineriai: Priklausomybių injekcijos automatizavimas
Rankinis priklausomybių valdymas gali tapti varginantis ir linkęs į klaidas, ypač didelėse programose. IoC konteineriai (taip pat žinomi kaip priklausomybių injekcijos konteineriai) yra sistemos, kurios automatizuoja priklausomybių kūrimo ir įšvirkštimo procesą. Jie suteikia centralizuotą vietą priklausomybių konfigūravimui ir jų išsprendimui vykdymo metu.
IoC konteinerių naudojimo privalumai
- Supaprastintas priklausomybių valdymas: IoC konteineriai automatiškai tvarko priklausomybių kūrimą ir injekciją.
- Centralizuota konfigūracija: Priklausomybės konfigūruojamos vienoje vietoje, todėl lengviau valdyti ir prižiūrėti programą.
- Pagerintas testuojamumas: IoC konteineriai leidžia lengvai konfigūruoti skirtingas priklausomybes testavimo tikslais.
- Pagerintas pakartotinis panaudojamumas: IoC konteineriai leidžia objektus lengvai pakartotinai naudoti skirtinguose kontekstuose su skirtingomis priklausomybėmis.
Populiarūs IoC konteineriai
Daugybė IoC konteinerių yra prieinami įvairioms programavimo kalboms. Kai kurie populiarūs pavyzdžiai:
- Spring Framework (Java): Išsami sistema, apimanti galingą IoC konteinerį.
- .NET Dependency Injection (C#): Integruotas DI konteineris .NET Core ir .NET.
- Laravel (PHP): Populiari PHP sistema su tvirtu IoC konteineriu.
- Symfony (PHP): Kita populiari PHP sistema su sudėtingu DI konteineriu.
- Angular (TypeScript): Vartotojo sąsajos sistema su integruota priklausomybių injekcija.
- NestJS (TypeScript): Node.js sistema, skirta kurti keičiamo dydžio serverio pusės programas.
Pavyzdys naudojant Laravel IoC konteinerį (PHP)
// Susieti sąsają su konkrečia implementacija
use App\Interfaces\PaymentGatewayInterface;
use App\Services\PayPalGateway;
$this->app->bind(PaymentGatewayInterface::class, PayPalGateway::class);
// Išspręsti priklausomybę
use App\Http\Controllers\OrderController;
public function store(Request $request, PaymentGatewayInterface $paymentGateway) {
// $paymentGateway yra automatiškai įšvirkščiamas
$order = new Order($request->all());
$paymentGateway->processPayment($order->total);
// ...
}
Šiame pavyzdyje Laravel IoC konteineris automatiškai išsprendžia PaymentGatewayInterface
priklausomybę OrderController
ir įšvirkščia PayPalGateway
egzempliorių.
Priklausomybių injekcijos ir valdymo inversijos privalumai
DI ir IoC pritaikymas siūlo daugybę privalumų programinės įrangos kūrimui:
Padidintas testuojamumas
DI žymiai palengvina vienetų testų rašymą. Įšvirkšdami imitacines ar fiktyvias priklausomybes, galite izoliuoti testuojamą komponentą ir patikrinti jo elgseną, nepasikliaudami išorinėmis sistemomis ar duomenų bazėmis. Tai yra labai svarbu norint užtikrinti kodo kokybę ir patikimumą.
Sumažintas susiejimas
Laisvas susiejimas yra pagrindinis gero programinės įrangos projektavimo principas. DI skatina laisvą susiejimą, mažindama priklausomybes tarp objektų. Tai daro kodą moduliškesnį, lankstesnį ir lengviau prižiūrimą. Vieno komponento pakeitimai mažiau tikėtina, kad paveiks kitas programos dalis.
Pagerintas prižiūrimumas
Programos, sukurtos naudojant DI, paprastai yra lengviau prižiūrimos ir modifikuojamos. Modulinis dizainas ir laisvas susiejimas palengvina kodo supratimą ir pakeitimų atlikimą neįvedant nenumatytų šalutinių poveikių. Tai ypač svarbu ilgalaikiams projektams, kurie vystosi laikui bėgant.
Pagerintas pakartotinis panaudojamumas
DI skatina kodo pakartotinį panaudojimą, darant komponentus labiau nepriklausomus ir autonomiškus. Komponentus galima lengvai pakartotinai naudoti skirtinguose kontekstuose su skirtingomis priklausomybėmis, sumažinant kodo dubliavimo poreikį ir gerinant bendrą kūrimo proceso efektyvumą.
Padidintas moduliškumas
DI skatina modulinį dizainą, kai programa yra padalinta į mažesnius, nepriklausomus komponentus. Tai palengvina kodo supratimą, testavimą ir modifikavimą. Tai taip pat leidžia skirtingoms komandoms vienu metu dirbti su skirtingomis programos dalimis.
Supaprastinta konfigūracija
IoC konteineriai suteikia centralizuotą vietą priklausomybių konfigūravimui, todėl lengviau valdyti ir prižiūrėti programą. Tai sumažina rankinio konfigūravimo poreikį ir pagerina bendrą programos nuoseklumą.
Geriausios priklausomybių injekcijos praktikos
Norėdami efektyviai naudoti DI ir IoC, apsvarstykite šias geriausias praktikas:
- Teikite pirmenybę konstruktoriaus injekcijai: Kai tik įmanoma, naudokite konstruktoriaus injekciją, kad užtikrintumėte, jog objektai gaus visas reikiamas priklausomybes kūrimo metu.
- Venkite paslaugų lokatoriaus (Service Locator) šablono: Paslaugų lokatoriaus šablonas gali paslėpti priklausomybes ir apsunkinti kodo testavimą. Vietoj to teikite pirmenybę DI.
- Naudokite sąsajas: Apibrėžkite sąsajas savo priklausomybėms, kad skatintumėte laisvą susiejimą ir pagerintumėte testuojamumą.
- Konfigūruokite priklausomybes centralizuotoje vietoje: Naudokite IoC konteinerį priklausomybėms valdyti ir konfigūruoti jas vienoje vietoje.
- Laikykitės SOLID principų: DI ir IoC yra glaudžiai susiję su objektinio projektavimo SOLID principais. Laikykitės šių principų, kad sukurtumėte tvirtą ir prižiūrimą kodą.
- Naudokite automatizuotą testavimą: Rašykite vienetų testus, kad patikrintumėte savo kodo elgseną ir užtikrintumėte, kad DI veikia teisingai.
Dažniausi antišablonai
Nors priklausomybių injekcija yra galingas įrankis, svarbu vengti dažniausių antišablonų, kurie gali pakenkti jos privalumams:
- Perteklinė abstrakcija: Venkite kurti nereikalingas abstrakcijas ar sąsajas, kurios prideda sudėtingumo, nesuteikdamos realios vertės.
- Paslėptos priklausomybės: Užtikrinkite, kad visos priklausomybės būtų aiškiai apibrėžtos ir įšvirkštos, o ne paslėptos kode.
- Objektų kūrimo logika komponentuose: Komponentai neturėtų būti atsakingi už savo priklausomybių kūrimą ar jų gyvavimo ciklo valdymą. Ši atsakomybė turėtų būti perduota IoC konteineriui.
- Glaudus susiejimas su IoC konteineriu: Venkite glaudžiai susieti savo kodą su konkrečiu IoC konteineriu. Naudokite sąsajas ir abstrakcijas, kad sumažintumėte priklausomybę nuo konteinerio API.
Priklausomybių injekcija skirtingose programavimo kalbose ir sistemose
DI ir IoC yra plačiai palaikomi įvairiose programavimo kalbose ir sistemose. Štai keletas pavyzdžių:
Java
Java kūrėjai priklausomybių injekcijai dažnai naudoja tokias sistemas kaip Spring Framework ar Guice.
@Component
public class ProductServiceImpl implements ProductService {
private final ProductRepository productRepository;
@Autowired
public ProductServiceImpl(ProductRepository productRepository) {
this.productRepository = productRepository;
}
// ...
}
C#
.NET teikia integruotą priklausomybių injekcijos palaikymą. Galite naudoti Microsoft.Extensions.DependencyInjection
paketą.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient();
services.AddTransient();
}
}
Python
Python siūlo bibliotekas, tokias kaip injector
ir dependency_injector
, skirtas DI įgyvendinimui.
from dependency_injector import containers, providers
class Container(containers.DeclarativeContainer):
database = providers.Singleton(Database, db_url="localhost")
user_repository = providers.Factory(UserRepository, database=database)
user_service = providers.Factory(UserService, user_repository=user_repository)
container = Container()
user_service = container.user_service()
JavaScript/TypeScript
Sistemos, tokios kaip Angular ir NestJS, turi integruotas priklausomybių injekcijos galimybes.
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class ProductService {
constructor(private http: HttpClient) {}
// ...
}
Realūs pavyzdžiai ir naudojimo atvejai
Priklausomybių injekcija taikoma įvairiausiuose scenarijuose. Štai keletas realių pavyzdžių:
- Prieiga prie duomenų bazės: Duomenų bazės ryšio arba repozitorijos injekcija, užuot ją kuriant tiesiogiai paslaugoje.
- Žurnalo įrašai: Žurnalo įrašymo (logger) egzemplioriaus injekcija, leidžianti naudoti skirtingas žurnalo įrašymo implementacijas, nekeičiant paslaugos.
- Mokėjimų šliuzai: Mokėjimų šliuzo injekcija, siekiant palaikyti skirtingus mokėjimų tiekėjus.
- Talpyklos (Caching) naudojimas: Talpyklos tiekėjo injekcija, siekiant pagerinti našumą.
- Pranešimų eilės: Pranešimų eilės kliento injekcija, siekiant atsaisti komponentus, kurie bendrauja asinchroniškai.
Išvada
Priklausomybių injekcija ir valdymo inversija yra fundamentalūs projektavimo principai, kurie skatina laisvą susiejimą, gerina testuojamumą ir didina programinės įrangos prižiūrimumą. Įvaldę šias technikas ir efektyviai naudodami IoC konteinerius, kūrėjai gali sukurti tvirtesnes, keičiamo dydžio ir lengviau pritaikomas sistemas. DI/IoC pritaikymas yra esminis žingsnis link aukštos kokybės programinės įrangos, atitinkančios šiuolaikinės kūrimo reikalavimus, kūrimo.