Princíp inverzie závislosti je implementovaný pomocou. Inverzia závislosti

Domov / Hádka

Vlastne všetky zásady PEVNÉ sú silne prepojené a ich hlavným cieľom je pomáhať vytvárať kvalitný, škálovateľný softvér. Ale posledná zásada PEVNÉ naozaj stojí proti nim. Najprv sa pozrime na formuláciu tohto princípu. takže, princíp inverzie závislosti (Princíp inverzie závislosti – DIP): „Závislosť na abstrakciách. Neexistuje žiadna závislosť na ničom konkrétnom.. Tento princíp vyzdvihuje aj notoricky známy odborník na vývoj softvéru Robert Martin DIP a prezentuje ho jednoducho ako výsledok dodržiavania iných zásad PEVNÉ— princíp otvorený/zatvorený a princíp Liskovovej substitúcie. Pripomeňme, že prvá hovorí, že trieda by sa nemala upravovať, aby sa robili nové zmeny, a druhá sa zaoberá dedením a predpokladá bezpečné používanie odvodených typov nejakého základného typu bez narušenia správnej činnosti programu. Robert Martin pôvodne formuloval tento princíp takto:

1). Moduly vyššej úrovne by nemali závisieť od modulov nižšej úrovne. Moduly na oboch úrovniach musia závisieť od abstrakcií.

2). Abstrakcie by nemali závisieť od detailov. Podrobnosti by mali závisieť od abstrakcií.

To znamená, že je potrebné vyvinúť triedy z hľadiska abstrakcií, a nie ich konkrétnych implementácií. A ak budete dodržiavať zásady OCP A LSP, tak to je presne to, čo dosiahneme. Preto sa vráťme trochu k lekcii ďalej. Tam sme ako príklad považovali triedu bard, ktorý bol na samom začiatku napevno naviazaný na triedu Gitara, ktorá predstavuje konkrétny hudobný nástroj:

verejná trieda Bard ( súkromná gitara gitara; verejná gitara (gitara) ( this.gitara = gitara; ) verejná void hra () ( gitara.hra (); ) )

verejná trieda Bard(

súkromná gitarová gitara;

verejný Bard (gitara)

toto. gitara = gitara ;

verejná neplatná hra ()

gitaru. hrať();

Ak by sme chceli do tejto triedy pridať podporu pre iné hudobné nástroje, tak by sme túto triedu museli nejako upraviť. Ide o jasné porušenie zásady OCP. A možno ste si už všimli, že ide aj o porušenia zásady DIP, keďže v našom prípade sa ukázalo, že naša abstrakcia je závislá od detailov. Z hľadiska ďalšieho rozširovania našej triedy to nie je vôbec dobré. Aby naša trieda spĺňala podmienky zásady OCP do systému sme pridali rozhranie nástroj, ktorá implementovala špecifické triedy reprezentujúce určité druhy hudobných nástrojov.

Súbor Instrument.java:

nástroj verejného rozhrania (void play(); )

nástroj verejného rozhrania(

voidplay();

Súbor Gitara.java:

class Gitara implementuje Instrument( @Override public void play() ( System.out.println("Play Guitar!"); ) )

trieda Nástroj na gitaru(

@Prepísať

verejná neplatná hra ()

Systém. von . println("Hraj na gitare!");

Súbor lutna.java:

public class Lute implementuje Instrument( @Override public void play() ( System.out.println("Play Lute!"); ) )

verejná trieda Lute implementuje Instrument(

@Prepísať

verejná neplatná hra ()

Systém. von . println("Hraj na lutnu!" );

Potom sme zmenili triedu bard aby sme v prípade potreby mohli implementácie nahradiť presne tými, ktoré potrebujeme. To prináša dodatočnú flexibilitu vytváranému systému a znižuje jeho súdržnosť (silné závislosti tried na sebe).

public class Bard ( private Instrument instrument; public Bard() ( ) public void play() ( instrument.play(); ) public void setInstrument(Instrument tool) ( this.instrument = instrument; ) )

verejná trieda Bard(

súkromný nástroj ;

2 odpovede

Dobrá poznámka - slovo inverzia je trochu prekvapujúce (keďže po použití DIP modul závislosti nižšej úrovne teraz zjavne nezávisí od modulu volajúceho na vyššej úrovni: buď volajúci alebo závislý je teraz voľnejšie spojený prostredníctvom ďalšej abstrakcie).

Možno sa pýtate, prečo používam slovo „inverzia“. Úprimne povedané, je to preto, že tradičnejšie metódy vývoja softvéru, ako je štruktúrovaná analýza a dizajn, majú tendenciu vytvárať softvérové ​​štruktúry, v ktorých moduly vysokej úrovne závisia od modulov nízkej úrovne a v ktorých abstrakcie závisia od detailov. V skutočnosti je jedným z účelov týchto metód definovať hierarchiu podprogramov, ktorá popisuje, ako moduly na vysokej úrovni volajú moduly nízkej úrovne.... Štruktúra závislostí dobre navrhnutého objektovo orientovaného programu je teda „obrátený“ vzhľadom na štruktúru závislosti, ktorá je zvyčajne výsledkom tradičných procedurálnych metód.

Jeden bod, ktorý si treba všimnúť pri čítaní článku strýka Boba o DIP, je, že C++ nemá (a v čase písania článku ani nemá) rozhrania, takže dosiahnutie tejto abstrakcie v C++ sa zvyčajne dosahuje prostredníctvom abstraktnej/čistej virtuálnej základnej triedy, zatiaľ čo v jazyku Java alebo C# abstrakcia na uvoľnenie spojenia je zvyčajne rozpojenie odstránením rozhrania zo závislosti a naviazaním modulu (modulov) vyššej úrovne na rozhranie.

Upraviť Len na objasnenie:

"Na niektorých miestach tiež vidím, že sa to nazýva inverzia závislosti"

Inverzia: Invertujte správu závislostí z aplikácie do kontajnera (ako Spring).

Injekcia závislosti:

Namiesto písania továrenského vzoru, čo tak vložiť objekt priamo do triedy klienta. Nechajme teda triedu klienta odkazovať na rozhranie a mali by sme byť schopní vložiť konkrétny typ do triedy klienta. Vďaka tomu trieda klienta nemusí používať kľúčové slovo new a je úplne oddelená od konkrétnych tried.

A čo inverzia kontroly (IoC)?

V tradičnom programovaní je tok obchodnej logiky definovaný objektmi, ktoré sú k sebe staticky priradené. Pri inverzii riadenia tok závisí od objektového grafu, ktorý vytvára inštanciu assembleru a umožňujú interakcie objektov definované prostredníctvom abstrakcií. Proces spájania sa dosahuje prostredníctvom injekcie závislosti, aj keď niektorí tvrdia, že používanie vyhľadávača služieb tiež poskytuje inverziu kontroly.

Inverzia riadenia ako sprievodca dizajnom slúži na tieto účely:

  • Dochádza k oddeleniu vykonávania konkrétnej úlohy od implementácie.
  • Každý modul sa môže zamerať na to, na čo je určený.
  • Moduly nerobia žiadne predpoklady o tom, čo robia iné systémy, ale spoliehajú sa na svoje zmluvy.
  • Výmena modulov nemá vplyv na ostatné moduly.

Ďalšie informácie nájdete v časti.

Posledná aktualizácia: 03/11/2016

Princíp inverzie závislosti(Princíp inverzie závislosti) sa používa na vytváranie voľne spojených entít, ktoré sa dajú ľahko testovať, upravovať a aktualizovať. Tento princíp možno formulovať takto:

Moduly najvyššej úrovne by nemali závisieť od modulov nižšej úrovne. Oboje musí závisieť od abstrakcií.

Abstrakcie by nemali závisieť od detailov. Podrobnosti by mali závisieť od abstrakcií.

Ak chcete pochopiť princíp, zvážte nasledujúci príklad:

Class Book ( public string Text ( get; set; ) public ConsolePrinter Printer ( get; set; ) public void Print() ( Printer.Print(Text); ) ) class ConsolePrinter ( public void Print(text string) ( Console.WriteLine (text); ) )

Trieda Book, ktorá predstavuje knihu, používa na tlač triedu ConsolePrinter. Keď je takto definovaná, trieda Book závisí od triedy ConsolePrinter. Navyše sme pevne zadefinovali, že tlač knihy je možná len na konzole pomocou triedy ConsolePrinter. Ďalšie možnosti, napríklad výstup na tlačiareň, výstup do súboru alebo použitie niektorých prvkov grafického rozhrania - to všetko je v tomto prípade vylúčené. Abstrakcia kníhtlače nie je oddelená od detailov triedy ConsolePrinter. Toto všetko je porušením princípu inverzie závislosti.

Teraz sa pokúsme zosúladiť naše triedy s princípom inverzie závislosti oddelením abstrakcií od nízkoúrovňovej implementácie:

Rozhranie IPrinter ( void Print(text string); ) class Book ( public string Text ( get; set; ) public IPrinter Printer ( get; set; ) public Book(IPrinter printer) ( this.Printer = printer; ) public void Print( ) ( Printer.Print(Text); ) ) class ConsolePrinter: IPrinter ( public void Print(reťazcový text) ( Console.WriteLine("Print to Console"); ) ) class HtmlPrinter: IPrinter ( public void Print(reťazcový text) ( Console.WriteLine("Tlač do html"); ) )

Teraz je kníhtlačová abstrakcia oddelená od konkrétnych realizácií. Výsledkom je, že trieda Book aj trieda ConsolePrinter závisia od abstrakcie IPrinter. Okrem toho teraz môžeme vytvárať aj ďalšie nízkoúrovňové implementácie abstrakcie IPrinter a dynamicky ich aplikovať v programe:

Kniha knihy = new Book(new ConsolePrinter()); kniha.Tlač(); kniha.Tlačiareň = new HtmlTlačiareň(); kniha.Tlač();

Inverzia závislostí je jedným z najdôležitejších programovacích idiómov. Na ruskojazyčnom internete je prekvapivo málo opisov tohto idiómu (princípu). Tak som sa rozhodol, že skúsim spraviť popis. Urobím príklady v Jave, momentálne je to pre mňa jednoduchšie, aj keď princíp inverzie závislostí je aplikovateľný na akýkoľvek programovací jazyk.

Tento popis bol vyvinutý v spolupráci s Vladimírom Matveevom v rámci prípravy na hodiny so študentmi Java.

Ďalšie články z tejto série:

Začnime s definíciou „závislosti“. Čo je závislosť? Ak váš kód interne používa nejakú triedu alebo explicitne volá statickú metódu nejakej triedy alebo funkcie, ide o závislosť. Vysvetlím na príkladoch:

Pod triedou A vnútri metódy s názvom someMethod() explicitne vytvorí objekt triedy B a pristúpi k jeho metóde someMethodOfB()

Verejná trieda A ( void someMethod() ( B b = new B(); b.someMethodOfB(); ) )

Podobne napríklad trieda B explicitne odkazuje na statické polia a metódy triedy System:

Verejná trieda B ( void someMethodOfB() ( System.out.println("Ahoj svet"); ) )

Vo všetkých prípadoch, keď akákoľvek trieda (typ A) sama vytvorí akúkoľvek triedu (typ B) alebo explicitne pristupuje k statickým poliam alebo členom triedy, nazýva sa to rovno závislosť. Tie. dôležité: ak trieda v sebe funguje v sebe s inou triedou, ide o závislosť. Ak si v sebe vytvorí aj túto triedu, tak toto rovno závislosť.

Čo je zlé na priamych závislostiach? Priame závislosti sú zlé v tom, že trieda, ktorá vo svojom vnútri nezávisle vytvára ďalšiu triedu, je s touto triedou „pevne“ zviazaná. Tie. ak je výslovne napísané, že B = nové B(); , potom bude trieda A vždy spolupracovať s triedou B a žiadna iná trieda. Alebo ak hovorí System.out.println("..."); potom bude trieda vždy výstup na System.out a nikde inde.

Pre malé triedy nie sú závislosti strašné. Takýto kód môže dobre fungovať. Ale v niektorých prípadoch, aby vaša trieda A fungovala univerzálne v prostredí rôznych tried, môže potrebovať iné implementácie tried závislostí. Tie. budete potrebovať napríklad nie triedu B , ale inú triedu s rovnakým rozhraním alebo nie System.out , ale napríklad výstup do loggeru (napríklad log4j).

Priama závislosť sa dá graficky zobraziť takto:

Tie. keď vo svojom kóde vytvoríte triedu A: A a = new A(); v skutočnosti nevzniká jedna trieda A, ale celá hierarchia závislých tried, ktorej príklad je na obrázku vyššie. Táto hierarchia je „tuhá“: bez zmeny zdrojového kódu jednotlivých tried nie je možné nahradiť žiadnu z tried v hierarchii. Preto je trieda A v takejto implementácii slabo adaptabilná na meniace sa prostredie. S najväčšou pravdepodobnosťou ho nebude možné použiť v žiadnom kóde, okrem konkrétneho kódu, pre ktorý ste ho napísali.

Ak chcete oddeliť triedu A od konkrétnych závislostí, použite injekcia závislosti. Čo je injekcia závislosti? Namiesto explicitného vytvorenia požadovanej triedy v kóde sa závislosti prenesú do triedy A prostredníctvom konštruktora:

Verejná trieda A ( private final B b; public A(B b) ( this.b = b; ) public void someMethod() ( b.someMethodOfB(); ) )

To. trieda A teraz získa svoju závislosť prostredníctvom konštruktora. Teraz, aby ste vytvorili triedu A, musíte najprv vytvoriť jej závislú triedu. V tomto prípade je to B:

B b = nové B (); A a = nové A(b); a.nejaká metóda();

Ak sa rovnaký postup zopakuje pre všetky triedy, t.j. odovzdajte inštanciu triedy D konštruktorovi triedy B, konštruktorovi triedy D — jej závislosti E a F atď., potom dostanete kód, ktorého všetky závislosti sú vytvorené v opačnom poradí:

Gg = nové G(); Hh = nové H(); F f = new(g,h); Ee = nové E(); Dd = nové D(e,f); Bb = nové B(d); A a = nové A(b); a.nejaká metóda();

Graficky to možno zobraziť takto:

Ak porovnáte 2 obrázky - obrázok vyššie s priamymi závislosťami a druhý obrázok s injekciou závislostí - môžete vidieť, že smer šípok sa zmenil na opačný. Z tohto dôvodu sa idióm nazýva „inverzia závislosti“. Inými slovami, inverzia závislostí spočíva v tom, že trieda nevytvára závislosti sama od seba, ale prijíma ich vo vytvorenej forme v konštruktore (alebo inak).

Prečo je inverzia závislosti dobrá? Pomocou inverzie závislostí môžete nahradiť všetky závislosti v triede bez zmeny jej kódu. A to znamená, že vaša trieda A môže byť flexibilne nakonfigurovaná na použitie v inom programe, než pre ktorý bola pôvodne napísaná. To. Princíp inverzie závislosti (niekedy nazývaný princíp vstrekovania závislosti) je kľúčom k vytvoreniu flexibilného, ​​modulárneho a opakovane použiteľného kódu.

Nevýhoda injekcie závislostí je tiež viditeľná na prvý pohľad - objekty tried navrhnutých pomocou tohto vzoru sú pracné na konštrukciu. Preto sa injekcia závislosti (inverzia) zvyčajne používa v spojení s nejakou knižnicou určenou na uľahčenie tejto úlohy. Napríklad jedna z knižníc Google Guice. Cm.

© 2023 skudelnica.ru -- Láska, zrada, psychológia, rozvod, city, hádky