Vra

Wat is die afhanklikheidsomkeringbeginsel en hoekom is dit belangrik?

Was dit nuttig?

Oplossing

Bevestig hierdie dokument uit:. Die Afhanklikheid Inversie Beginsel

Dit sê basies:

  • Hoë vlak modules moet nie afhang van 'n lae-vlak modules. Beide moet afhang van abstraksies.
  • abstraksies moet nooit afhanklik van besonderhede. Besonderhede moet afhang van abstraksies.

As aan waarom dit belangrik is, in kort:. Veranderinge is riskant, en deur na gelang van 'n konsep in plaas van op 'n uitvoering, jy die behoefte vir verandering by oproep webwerwe verminder

In feite is die DIP verminder koppeling tussen verskillende stukke van die kode. Die idee is dat hoewel daar is baie maniere om die implementering, sê, 'n te meld fasiliteit, die manier sou jy dit gebruik moet relatief stabiel in tyd wees. As jy 'n koppelvlak wat die konsep van meld verteenwoordig kan onttrek, moet hierdie koppelvlak baie meer stabiel in tyd as die implementering daarvan wees, en oproep webwerwe moet veel minder geraak deur die veranderinge wat jy kan maak, terwyl die handhawing of die uitbreiding van wat meld meganisme.

Deur ook die maak van die implementering afhang van 'n koppelvlak, kry jy die geleentheid om te kies by run-time, wat implementering is beter geskik vir jou spesifieke omgewing. Afhangende van die gevalle, kan dit interessant te wees.

Ander wenke

Die boeke Agile Sagteware-ontwikkeling, Beginsels, Patrone en Praktyke en Agile Beginsels, Patrone en Praktyke in C# is die beste hulpbronne om die oorspronklike doelwitte en motiverings agter die Afhanklikheidsinversiebeginsel ten volle te verstaan.Die artikel "The Dependency Inversion Principle" is ook 'n goeie hulpbron, maar as gevolg van die feit dat dit 'n verkorte weergawe is van 'n konsep wat uiteindelik sy plek in die voorheen genoemde boeke gemaak het, laat dit 'n paar belangrike bespreking oor die konsep van 'n pakket- en koppelvlakeienaarskap wat die sleutel is om hierdie beginsel te onderskei van die meer algemene advies om "te programmeer na 'n koppelvlak, nie 'n implementering nie" wat in die boek Design Patterns (Gamma, et.al).

Om 'n opsomming te gee, gaan die Afhanklikheidsinversiebeginsel hoofsaaklik oor omkeer die konvensionele rigting van afhanklikhede van "hoër vlak" komponente na "laer vlak" komponente sodat "laer vlak" komponente afhanklik is van die koppelvlakke owned deur die "hoër vlak" komponente.(Let wel:"hoër vlak" komponent verwys hier na die komponent wat eksterne afhanklikhede/dienste vereis, nie noodwendig sy konseptuele posisie binne 'n gelaagde argitektuur nie.) Sodoende is koppeling nie verminder soveel as wat dit is verskuif van komponente wat teoreties minder waardevol is tot komponente wat teoreties meer waardevol is.

Dit word bereik deur komponente te ontwerp waarvan die eksterne afhanklikhede uitgedruk word in terme van 'n koppelvlak waarvoor 'n implementering deur die verbruiker van die komponent verskaf moet word.Met ander woorde, die gedefinieerde koppelvlakke druk uit wat die komponent benodig, nie hoe jy die komponent gebruik nie (bv."INeedSomething", nie "IDoSomething" nie).

Waarna die afhanklikheidsomkeringbeginsel nie verwys nie, is die eenvoudige praktyk om afhanklikhede te onttrek deur die gebruik van koppelvlakke (bv.MyService → [ILogger ⇐ Logger]).Alhoewel dit 'n komponent van die spesifieke implementeringsdetail van die afhanklikheid ontkoppel, keer dit nie die verhouding tussen die verbruiker en afhanklikheid om nie (bv.[MyService → IMyServiceLogger] ⇐ Logger.

Die belangrikheid van die afhanklikheidsomkeringbeginsel kan afgelei word na 'n enkele doelwit om sagtewarekomponente te kan hergebruik wat op eksterne afhanklikhede staatmaak vir 'n gedeelte van hul funksionaliteit (logboek, validering, ens.)

Binne hierdie algemene doel van hergebruik kan ons twee subtipes hergebruik afbaken:

  1. Die gebruik van 'n sagteware-komponent binne veelvuldige toepassings met sub-afhanklikheidsimplementerings (bv.Jy het 'n DI-houer ontwikkel en wil logging verskaf, maar wil nie jou houer aan 'n spesifieke logger koppel sodat almal wat jou houer gebruik ook jou gekose logging-biblioteek moet gebruik nie).

  2. Die gebruik van sagtewarekomponente binne 'n ontwikkelende konteks (bv.Jy het besigheidslogika-komponente ontwikkel wat dieselfde bly oor verskeie weergawes van 'n toepassing waar die implementeringbesonderhede ontwikkel).

Met die eerste geval van hergebruik van komponente oor veelvuldige toepassings, soos met 'n infrastruktuurbiblioteek, is die doel om 'n kerninfrastruktuurbehoefte aan jou verbruikers te voorsien sonder om jou verbruikers aan subafhanklikhede van jou eie biblioteek te koppel, aangesien die neem van afhanklikhede van sulke afhanklikhede jou vereis verbruikers om dieselfde afhanklikhede ook te vereis.Dit kan problematies wees wanneer verbruikers van jou biblioteek kies om 'n ander biblioteek vir dieselfde infrastruktuurbehoeftes te gebruik (bv.NLog vs.log4net), of as hulle kies om 'n latere weergawe van die vereiste biblioteek te gebruik wat nie agteruit versoenbaar is met die weergawe wat deur jou biblioteek vereis word nie.

Met die tweede geval van hergebruik van besigheidslogika-komponente (d.w.s."hoërvlakkomponente"), is die doel om die kerndomeinimplementering van u toepassing te isoleer van die veranderende behoeftes van u implementeringsbesonderhede (d.w.s.verandering/opgradering van volhardingsbiblioteke, boodskapbiblioteke, enkripsiestrategieë, ens.).Ideaal gesproke behoort die verandering van die implementeringsbesonderhede van 'n toepassing nie die komponente wat die toepassing se besigheidslogika insluit, te breek nie.

Let wel:Sommige kan beswaar maak om hierdie tweede geval as werklike hergebruik te beskryf, en redeneer dat komponente soos besigheidslogika-komponente wat binne 'n enkele ontwikkelende toepassing gebruik word, slegs 'n enkele gebruik verteenwoordig.Die idee hier is egter dat elke verandering aan die toepassing se implementeringsbesonderhede 'n nuwe konteks en dus 'n ander gebruiksgeval gee, alhoewel die uiteindelike doelwitte onderskei kan word as isolasie vs.oordraagbaarheid.

Alhoewel die navolging van die Afhanklikheidsinversiebeginsel in hierdie tweede geval 'n mate van voordeel kan bied, moet daarop gelet word dat die waarde daarvan soos toegepas op moderne tale soos Java en C# baie verminder is, miskien tot die punt dat dit irrelevant is.Soos vroeër bespreek, behels die DIP die implementering van besonderhede in aparte pakkette heeltemal te skei.In die geval van 'n ontwikkelende toepassing, sal bloot die gebruik van koppelvlakke wat in terme van die besigheidsdomein gedefinieer word, egter daarteen waak om hoërvlakkomponente te verander as gevolg van veranderende behoeftes van implementeringsdetailkomponente, selfs al is die implementeringsbesonderhede uiteindelik binne dieselfde pakket.Hierdie gedeelte van die beginsel weerspieël aspekte wat pertinent was vir die taal in die oog toe die beginsel gekodifiseer is (d.w.s.C++) wat nie relevant is vir nuwer tale nie.Dit gesê, die belangrikheid van die afhanklikheidsomkering-beginsel lê hoofsaaklik by die ontwikkeling van herbruikbare sagtewarekomponente/biblioteke.

'n Langer bespreking van hierdie beginsel, aangesien dit verband hou met die eenvoudige gebruik van koppelvlakke, Afhanklikheidsinspuiting en die Separated Interface-patroon kan gevind word hier.Daarbenewens kan 'n bespreking gevind word van hoe die beginsel verband hou met dinamies-getikte tale soos JavaScript hier.

Wanneer ons ontwerp sagteware programme kan ons kyk na die lae vlak klasse die klasse wat basiese en primêre bedrywighede te implementeer (toegang skyf, netwerkprotokolle, ...) en 'n hoë vlak klasse die klasse wat komplekse logika (besigheidsvloeie omsluit, .. .).

Die laaste wat staatmaak op die lae vlak klasse. 'N natuurlike manier van die uitvoering van sulke strukture sou wees om 'n lae vlak klasse skryf en sodra ons hulle om die komplekse hoë vlak klasse skryf. Sedert hoë vlak klasse gedefinieer in terme van ander dit lyk die logiese manier om dit te doen. Maar dit is nie 'n buigsame ontwerp. Wat gebeur as wat ons nodig het om 'n lae vlak klas vervang?

Die Afhanklikheid Inversie Beginsel bepaal dat:

  • Hoë vlak modules moet nie afhang van 'n lae vlak modules. Beide moet afhang van abstraksies.
  • abstraksies moet nie afhang van besonderhede. Besonderhede moet afhang van abstraksies.

Hierdie beginsel poog om "Keer" die konvensionele idee dat 'n hoë vlak modules in sagteware moet afhang van die laer vlak modules. Hier hoë vlak modules eienaar van die onttrekking (byvoorbeeld, besluit die metodes van die koppelvlak) wat in werking gestel word deur laer vlak modules. Waardeur laer vlak modules afhanklik van 'n hoër vlak modules.

Vir my is die Afhanklikheid Inversie Beginsel, soos beskryf in die amptelike artikel , is regtig 'n verkeerde poging om die herbruikbaarheid van modules wat inherent is minder herbruikbare verhoog, sowel as 'n manier om 'n probleem tydelike oplossing in die C ++ taal.

Die kwessie in C ++, is dat header lêers tipies bevat verklarings van private velde en metodes. Daarom, as 'n hoë-vlak C ++ module die kop lêer vir 'n lae-vlak module sluit, sal dit afhang van die werklike implementering details van die betrokke module. En dat, natuurlik, is nie 'n goeie ding. Maar dit is nie 'n probleem in die meer moderne tale vandag algemeen gebruik word.

Hoëvlak modules is inherent minder herbruikbare as 'n lae-vlak modules omdat die voormalige is gewoonlik meer application / konteks spesifiek as die laasgenoemde. Byvoorbeeld, 'n komponent wat 'n UI skerm implemente is van die hoogste vlak en ook baie (heeltemal?) Wat spesifiek op die aansoek. Probeer om so 'n komponent hergebruik in 'n ander aansoek is teenproduktief, en kan net lei tot oor-ingenieurswese.

So, die skepping van 'n aparte onttrekking op dieselfde vlak van 'n komponent A wat afhanklik is van 'n komponent van Amerika (wat nie afhang van A) kan slegs gedoen word indien komponent A regtig nuttig vir hergebruik in verskillende programme of sal wees kontekste. As dit nie die geval is, dan aansoek doen DIP sou sleg ontwerp wees.

Afhanklikheidsomkering wat goed toegepas word, gee buigsaamheid en stabiliteit op die vlak van die hele argitektuur van jou toepassing.Dit sal jou aansoek toelaat om veiliger en stabieler te ontwikkel.

Tradisionele gelaagde argitektuur

Tradisioneel het 'n gelaagde argitektuur-UI van die besigheidslaag afgehang en dit het weer van die datatoegangslaag afgehang.

http://xurxodev.com/content/images/2016/02/Traditional-Layered.png

Jy moet laag, pakket of biblioteek verstaan.Kom ons kyk hoe die kode sou wees.

Ons sal 'n biblioteek of pakket hê vir die datatoegangslaag.

// DataAccessLayer.dll
public class ProductDAO {

}

En nog 'n biblioteek- of pakketlaag besigheidslogika wat afhang van die datatoegangslaag.

// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO { 
    private ProductDAO productDAO;
}

Gelaagde argitektuur met afhanklikheidsomkering

Die afhanklikheidsomkering dui op die volgende:

Hoëvlakmodules behoort nie van laevlakmodules afhanklik te wees nie.Beide moet afhang van abstraksies.

Abstraksies moet nie van besonderhede afhang nie.Besonderhede moet afhang van abstraksies.

Wat is die hoëvlakmodules en laevlak?Dinkmodules soos biblioteke of pakkette, hoëvlakmodules sal dié wees wat tradisioneel afhanklikhede en lae vlak het waarop hulle afhanklik is.

Met ander woorde, module hoë vlak sal wees waar die aksie opgeroep word en lae vlak waar die aksie uitgevoer word.

'n Redelike gevolgtrekking om uit hierdie beginsel te maak, is dat daar geen afhanklikheid tussen konkresies moet wees nie, maar daar moet 'n afhanklikheid van 'n abstraksie wees.Maar volgens die benadering wat ons volg, kan ons beleggingsafhanklikheid verkeerd toepas, maar 'n abstraksie.

Stel jou voor dat ons ons kode soos volg aanpas:

Ons sal 'n biblioteek of pakket hê vir die datatoegangslaag wat die abstraksie definieer.

// DataAccessLayer.dll
public interface IProductDAO
public class ProductDAO : IProductDAO{

}

En nog 'n biblioteek- of pakketlaag besigheidslogika wat afhang van die datatoegangslaag.

// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO { 
    private IProductDAO productDAO;
}

Alhoewel ons op 'n abstraksie afhanklik is, bly afhanklikheid tussen besigheid en datatoegang dieselfde.

http://xurxodev.com/content/images/2016/02/Traditional-Layered.png

Om afhanklikheidsomkering te kry, moet die volhardingskoppelvlak gedefinieer word in die module of pakket waar hierdie hoëvlaklogika of domein is en nie in die laevlakmodule nie.

Definieer eers wat die domeinlaag is en die abstraksie van sy kommunikasie is gedefinieer volharding.

// Domain.dll
public interface IProductRepository;

using DataAccessLayer;
public class ProductBO { 
    private IProductRepository productRepository;
}

Nadat die volhardingslaag van die domein afhang, moet u nou omkeer as 'n afhanklikheid gedefinieer word.

// Persistence.dll
public class ProductDAO : IProductRepository{

}

http://xurxodev.com/content/images/2016/02/Dependency-Inversion-Layers.png

Verdieping van die beginsel

Dit is belangrik om die konsep goed te assimileer, wat die doel en voordele verdiep.As ons meganies inbly en die tipiese gevallebewaarplek leer, sal ons nie kan identifiseer waar ons die beginsel van afhanklikheid kan toepas nie.

Maar hoekom keer ons 'n afhanklikheid om?Wat is die hoofdoelwit buiten spesifieke voorbeelde?

So algemeen laat die mees stabiele dinge, wat nie van minder stabiele dinge afhanklik is nie, meer gereeld verander.

Dit is makliker vir die tipe volharding om te verander, hetsy die databasis of tegnologie om toegang tot dieselfde databasis te kry as die domeinlogika of aksies wat ontwerp is om met volharding te kommunikeer.As gevolg hiervan word die afhanklikheid omgekeer, want dit is makliker om die volharding te verander as hierdie verandering plaasvind.Op hierdie manier hoef ons nie die domein te verander nie.Die domeinlaag is die mees stabiele van almal, en daarom behoort dit van niks afhanklik te wees nie.

Maar daar is nie net hierdie bewaarplekvoorbeeld nie.Daar is baie scenario's waar hierdie beginsel van toepassing is en daar is argitekture wat op hierdie beginsel gebaseer is.

Argitekture

Daar is argitekture waar afhanklikheidsomkering die sleutel tot die definisie daarvan is.In al die domeine is dit die belangrikste en dit is abstraksies wat die kommunikasieprotokol tussen die domein en die res van die pakkette of biblioteke gedefinieer sal aandui.

Skoon argitektuur

In Skoon argitektuur die domein is in die middel geleë en as jy kyk in die rigting van die pyle wat afhanklikheid aandui, is dit duidelik wat die belangrikste en stabielste lae is.Die buitenste lae word as onstabiele gereedskap beskou, dus vermy om daarvan afhanklik te wees.

Seskantige argitektuur

Dit gebeur op dieselfde manier met die seskantige argitektuur, waar die domein ook in die sentrale deel geleë is en hawens is abstraksies van kommunikasie vanaf die domino na buite.Hier is dit weer duidelik dat die domein die mees stabiele is en tradisionele afhanklikheid is omgekeerd.

Eintlik is dit sê:

Klas moet afhang van abstraksies (bv koppelvlak, abstrakte klasse), nie spesifieke besonderhede (implementering).

'n Baie duideliker manier om die afhanklikheidsinversiebeginsel te stel, is:

Jou modules wat komplekse besigheidslogika omsluit behoort nie direk afhanklik te wees van ander modules wat besigheidslogika omsluit nie.In plaas daarvan moet hulle slegs afhang van koppelvlakke na eenvoudige data.

Dit wil sê, in plaas daarvan om jou klas te implementeer Logic soos mense gewoonlik doen:

class Dependency { ... }
class Logic {
    private Dependency dep;
    int doSomething() {
        // Business logic using dep here
    }
}

jy moet iets doen soos:

class Dependency { ... }
interface Data { ... }
class DataFromDependency implements Data {
    private Dependency dep;
    ...
}
class Logic {
    int doSomething(Data data) {
        // compute something with data
    }
}

Data en DataFromDependency moet in dieselfde module woon as Logic, nie met nie Dependency.

Hoekom dit doen?

  1. Die twee besigheidslogika-modules is nou ontkoppel.Wanneer Dependency verander, jy hoef nie te verander nie Logic.
  2. Verstaan ​​wat Logic doen is 'n baie eenvoudiger taak:dit werk net op wat lyk soos 'n ADT.
  3. Logic kan nou makliker getoets word.Jy kan nou direk instansieer Data met vals data en gee dit in.Geen behoefte aan bespottings of komplekse toetssteierwerk nie.

Goeie antwoorde en goeie voorbeelde is reeds deur ander hier.

Die rede DIP belangrik is, is omdat dit verseker die OO-beginsel "losweg gekoppel ontwerp ".

Die voorwerpe in jou sagteware moet nie in 'n hiërargie waar 'n paar voorwerpe is die top-vlak kinders, afhanklik is van 'n lae-vlak voorwerpe. Veranderinge in 'n lae-vlak voorwerpe sal dan uitkring-tot jou top-vlak voorwerpe wat die sagteware baie broos vir 'n verandering maak.

Jy wil jou 'n top-vlak 'voorwerpe om baie stabiel en nie broos vir 'n verandering wees, daarom moet jy die afhanklikhede Keer.

Inversie van beheer (IOK) is 'n ontwerp patroon waar 'n voorwerp kry oorhandig sy afhanklikheid deur 'n buite-raamwerk, eerder as om 'n raamwerk te vra vir sy afhanklikheid.

pseudokode voorbeeld gebruik te maak van tradisionele lookup:

class Service {
    Database database;
    init() {
        database = FrameworkSingleton.getService("database");
    }
}

Soortgelyke kode behulp IoC:

class Service {
    Database database;
    init(database) {
        this.database = database;
    }
}

Die voordele van die IOC is:

  • Jy het geen afhanklikheid van 'n sentrale raamwerk, so dit kan verander word indien wense oor.
  • Sedert voorwerpe geskep deur inspuiting, verkieslik met behulp van koppelvlakke, is dit maklik om eenheid te skep toetse wat afhanklikhede te vervang met spot weergawes.
  • Ontkoppeling af kode.

Die punt van afhanklikheid inversie is om herbruikbare sagteware maak.

Die idee is dat in plaas van twee stukke kode vertrou op mekaar steun hulle op 'n paar onttrek koppelvlak. Dan kan jy óf stuk hergebruik sonder die ander.

Die wyse waarop hierdie is die mees algemeen behaal is deur 'n omkering van beheer (IOK) houer soos Lente in Java. In hierdie model, is eienskappe van voorwerpe opgestel deur 'n XML opset in plaas van die voorwerpe uit te gaan en vind hul afhanklikheid.

Verbeel jou hierdie pseudokode ...

public class MyClass
{
  public Service myService = ServiceLocator.service;
}

MyClass direk afhanklik van beide die Service klas en die ServiceLocator klas. Dit moet beide van diegene as jy wil om dit te gebruik in 'n ander program. Nou dink hierdie ...

public class MyClass
{
  public IService myService;
}

Nou, MyClass staatmaak op 'n enkele koppelvlak, die IService koppelvlak. Ons wil laat die IOK houer eintlik die waarde van daardie veranderlike stel.

So nou, MyClass kan maklik weer gebruik in ander projekte, sonder om die afhanklikheid van die ander twee klasse saam met dit.

Selfs beter, hoef jy nie aan die afhanklikes van MyService, en die afhanklikhede van die afhanklikhede, en die ... wel, jy kry die idee sleep.

Inversie van Beheer Houers en die Afhanklikheid inspuiting patroon deur Martin Fowler is 'n goeie lees te . Ek het gevind dat kop eerste Design Patterns 'n awesome boek vir my eerste inval in leer DI en ander patrone.

Afhanklikheid inversie: Afhang van abstraksies, nie op konkresies

.

Inversie van beheer: Main vs abstraksie, en hoe die Main is die gom van die stelsels

.

DIP en IOK

Hierdie is 'n paar goeie poste praat oor hierdie:

https: // coderstower. com / 2019/03/26 / afhanklikheid-inversie-hoekom-jy-behoort nie-vermy-dit /

https://coderstower.com/ 2019/04/02 / hoof-en-onttrekking-die-ontkoppelde-eweknieë /

https://coderstower.com/ 2019/04/09 / inversie-van-beheer-om-all-saam /

Afhanklikheid Inversie Beginsel (DIP) sê dat

i) Hoë vlak modules moet nie afhang van 'n lae-vlak modules. Beide moet afhang van abstraksies.

ii) abstraksies moet nooit afhanklik van besonderhede. Besonderhede moet afhang van abstraksies.

Voorbeeld:

    public interface ICustomer
    {
        string GetCustomerNameById(int id);
    }

    public class Customer : ICustomer
    {
        //ctor
        public Customer(){}

        public string GetCustomerNameById(int id)
        {
            return "Dummy Customer Name";
        }
    }

    public class CustomerFactory
    {
        public static ICustomer GetCustomerData()
        {
            return new Customer();
        }
    }

    public class CustomerBLL
    {
        ICustomer _customer;
        public CustomerBLL()
        {
            _customer = CustomerFactory.GetCustomerData();
        }

        public string GetCustomerNameById(int id)
        {
            return _customer.GetCustomerNameById(id);
        }
    }

    public class Program
    {
        static void Main()
        {
            CustomerBLL customerBLL = new CustomerBLL();
            int customerId = 25;
            string customerName = customerBLL.GetCustomerNameById(customerId);


            Console.WriteLine(customerName);
            Console.ReadKey();
        }
    }

Let wel:. Klas moet afhang van abstraksies soos koppelvlak of abstrakte klasse, nie spesifieke besonderhede (implementering van koppelvlak)

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top