Կախվածության ինվերսիայի սկզբունքն իրականացվում է օգտագործելով. Կախվածության ինվերսիա

տուն / Վիճաբանություն

Իրականում բոլոր սկզբունքները պինդսերտորեն փոխկապակցված են և նրանց հիմնական նպատակն է օգնել ստեղծել բարձրորակ, մասշտաբային ծրագրակազմ: Բայց վերջին սկզբունքը պինդիսկապես առանձնանում է նրանց դեմ: Նախ, եկեք նայենք այս սկզբունքի ձևակերպմանը: Այսպիսով, կախվածության ինվերսիայի սկզբունքը (Կախվածության ինվերսիոն սկզբունք - DIP): «Կախվածություն աբստրակցիաներից. Ոչ մի կոնկրետ բանից կախվածություն չկա։. Ծրագրային ապահովման զարգացման հայտնի փորձագետ Ռոբերտ Մարտինը նույնպես կարևորում է սկզբունքը DIPև դա ներկայացնում է պարզապես որպես այլ սկզբունքներին հետևելու արդյունք պինդ— բաց/փակ սկզբունքը և Լիսկովի փոխարինման սկզբունքը։ Հիշեցնենք, որ առաջինն ասում է, որ դասը չպետք է փոփոխվի նոր փոփոխություններ կատարելու համար, իսկ երկրորդը վերաբերում է ժառանգությանը և ենթադրում է որոշ հիմնական տիպի ստացված տիպերի անվտանգ օգտագործում՝ առանց ծրագրի ճիշտ աշխատանքը խախտելու: Ռոբերտ Մարտինն ի սկզբանե ձևակերպել է այս սկզբունքը հետևյալ կերպ.

մեկը): Վերին մակարդակի մոդուլները չպետք է կախված լինեն ստորին մակարդակի մոդուլներից: Երկու մակարդակների մոդուլները պետք է կախված լինեն աբստրակցիաներից:

2). Աբստրակցիան չպետք է կախված լինի մանրամասներից։ Մանրամասները պետք է կախված լինեն աբստրակցիաներից:

Այսինքն՝ անհրաժեշտ է դասեր զարգացնել աբստրակցիաների, այլ ոչ թե դրանց կոնկրետ իրականացումների առումով։ Եվ եթե դուք հետևում եք սկզբունքներին OCPև LSP, ուրեմն հենց դրան էլ կհասնենք։ Հետևաբար, եկեք մի փոքր վերադառնանք դասին: Այնտեղ, որպես օրինակ, մենք դիտարկեցինք դասարանը բարդ, որը հենց սկզբում ծանրաբեռնված էր դասարանին Կիթառ, որը ներկայացնում է որոշակի երաժշտական ​​գործիք.

հանրային դասի Բարդ ( մասնավոր կիթառ կիթառ; հանրային Բարդ (կիթառ կիթառ) (այս. կիթառ = կիթառ; ) հանրային դատարկ նվագարկում () ( guitar.play(); )

հասարակական կարգ Բարդ (

մասնավոր կիթառ կիթառ;

հանրային բարդ (կիթառ կիթառ)

սա. կիթառ = կիթառ;

հանրային դատարկ խաղ ()

կիթառ. խաղալ ();

Եթե ​​մենք ցանկանում ենք այս դասին ավելացնել այլ երաժշտական ​​գործիքների աջակցություն, ապա մենք ինչ-որ կերպ պետք է փոփոխենք այս դասը: Սա սկզբունքի ակնհայտ խախտում է OCP. Եվ գուցե արդեն նկատել եք, որ դրանք նույնպես սկզբունքի խախտումներ են DIP, քանի որ մեր դեպքում մեր աբստրակցիան կախված է դետալներից։ Մեր դասի հետագա ընդլայնման տեսանկյունից սա ամենևին էլ լավ չէ։ Որպեսզի մեր դասարանը համապատասխանի սկզբունքի պայմաններին OCPմենք ինտերֆեյս ենք ավելացրել համակարգին գործիք, որն իրականացրել է երաժշտական ​​գործիքների որոշակի տեսակներ ներկայացնող հատուկ դասեր։

Ֆայլ Instrument.java:

հանրային ինտերֆեյսի գործիք (void play();)

հանրային ինտերֆեյսի գործիք (

voidplay ();

Ֆայլ Guitar.java:

class Guitar implements Instrument( @Override public void play() ( System.out.println(«Play Guitar»); ) )

դասի կիթառի գործիքների գործիք (

@Override

հանրային դատարկ խաղ ()

Համակարգ. դուրս . println («Կիթառ նվագել»);

Ֆայլ lute.java:

հանրային դասի Lute-ն իրականացնում է գործիք (@Override public void play() ( System.out.println ("Play Lute!"); ) )

հանրային դասի Լյութի իրագործման գործիք (

@Override

հանրային դատարկ խաղ ()

Համակարգ. դուրս . println («Խաղալ լյութ» );

Դրանից հետո մենք փոխեցինք դասարանը բարդորպեսզի անհրաժեշտության դեպքում իրականացումները փոխարինենք հենց մեզ անհրաժեշտով։ Սա լրացուցիչ ճկունություն է հաղորդում ստեղծվող համակարգին և նվազեցնում դրա համախմբվածությունը (դասակարգային ուժեղ կախվածություն միմյանցից):

հանրային դաս Bard ( մասնավոր գործիքային գործիք; հանրային Bard() ( ) public void play() ( instrument.play(); ) public void setInstrument(Instrument instrument) ( this.instrument = գործիք; ) )

հասարակական կարգ Բարդ (

մասնավոր գործիքային գործիք;

2 պատասխան

Լավ կետ. ինվերսիա բառը որոշ չափով զարմանալի է (քանի որ DIP կիրառելուց հետո, ավելի ցածր մակարդակի կախվածության մոդուլը, ըստ երևույթին, այժմ կախված չէ ավելի բարձր մակարդակի զանգահարողի մոդուլից. կա՛մ զանգահարողը, կա՛մ կախվածն այժմ ավելի թույլ է զուգակցվում լրացուցիչ վերացականության միջոցով: ):

Դուք կարող եք հարցնել, թե ինչու եմ ես օգտագործում «ինվերսիա» բառը: Անկեղծ ասած, դա պայմանավորված է նրանով, որ ծրագրային ապահովման մշակման ավելի ավանդական մեթոդները, ինչպիսիք են կառուցվածքային վերլուծությունը և դիզայնը, հակված են ստեղծելու ծրագրային կառուցվածքներ, որոնցում բարձր մակարդակի մոդուլները կախված են ցածր մակարդակի մոդուլներից, իսկ աբստրակցիաները՝ մանրամասներից: Փաստորեն, այս մեթոդների նպատակներից մեկը ենթածրագրերի հիերարխիա սահմանելն է, որը նկարագրում է, թե ինչպես են բարձր մակարդակի մոդուլները զանգեր կատարում դեպի ցածր մակարդակի մոդուլներ... Այսպիսով, լավ մշակված օբյեկտի վրա հիմնված ծրագրի կախվածության կառուցվածքը. «շրջված» կախվածության կառուցվածքի նկատմամբ, որը սովորաբար ավանդական ընթացակարգային մեթոդների արդյունք է։

Մի կետ, որը պետք է ուշադրություն դարձնել, երբ կարդում եք Uncle Bob-ի աշխատանքը DIP-ի վերաբերյալ, այն է, որ C++-ը չունի (և գրելու պահին չունի) միջերեսներ, ուստի C++-ում այս աբստրակցիային հասնելը սովորաբար ձեռք է բերվում վերացական/մաքուր վիրտուալ բազային դասի միջոցով, մինչդեռ Java-ում: կամ C# աբստրակցիան, որը թուլացնում է զուգավորումը, սովորաբար պետք է անջատվի՝ ինտերֆեյսը վերացելով կախվածությունից և կապելով ավելի բարձր մակարդակի մոդուլ(ներ)ը ինտերֆեյսին:

ԽմբագրելՊարզապես պարզաբանելու համար.

«Ինչ-որ տեղ ես նաև տեսնում եմ, որ դա կոչվում է կախվածության ինվերսիա»

Ինվերսիա:Փոխարկել կախվածության կառավարումը հավելվածից կոնտեյներ (ինչպես Spring):

Կախվածության ներարկում.

Գործարանային օրինաչափություն գրելու փոխարեն, ի՞նչ կասեք օբյեկտը ուղղակիորեն հաճախորդի դասի մեջ ներարկելու մասին: Այսպիսով, եկեք թույլ տանք, որ հաճախորդի դասը վերաբերի ինտերֆեյսին, և մենք պետք է կարողանանք կոնկրետ տեսակը ներարկել հաճախորդի դասի մեջ: Սրանով հաճախորդի դասը կարիք չունի օգտագործելու նոր բանալի բառը և ամբողջովին առանձնացված է կոնկրետ դասերից։

Ինչ վերաբերում է հսկողության ինվերսիային (IoC):

Ավանդական ծրագրավորման մեջ բիզնես տրամաբանության հոսքը սահմանվում է առարկաներով, որոնք ստատիկորեն վերագրվում են միմյանց: Վերահսկիչի հակադարձման դեպքում հոսքը կախված է օբյեկտի գրաֆիկից, որը ստեղծվում է մոնտաժողի կողմից և հնարավոր է դառնում աբստրակցիաների միջոցով սահմանված օբյեկտների փոխազդեցությունների շնորհիվ: Փաթեթավորման գործընթացը ձեռք է բերվում կախվածության ներարկման միջոցով, թեև ոմանք պնդում են, որ ծառայության տեղորոշիչի օգտագործումը նաև ապահովում է հսկողության հակադարձում:

Վերահսկիչի հակադարձումը որպես դիզայնի ուղեցույց ծառայում է հետևյալ նպատակներին.

  • Կա որոշակի առաջադրանքի կատարման անջատում իրականացումից:
  • Յուրաքանչյուր մոդուլ կարող է կենտրոնանալ այն բանի վրա, թե ինչի համար է այն նախատեսված:
  • Մոդուլները որևէ ենթադրություն չեն անում այն ​​մասին, թե ինչ են անում այլ համակարգերը, այլ հիմնվում են իրենց պայմանագրերի վրա:
  • Մոդուլների փոխարինումը չի ազդում այլ մոդուլների վրա:

Լրացուցիչ տեղեկությունների համար տե՛ս:

Վերջին թարմացումը՝ 03/11/2016

Կախվածության ինվերսիայի սկզբունքը(Կախվածության հակադարձման սկզբունքը) օգտագործվում է թույլ զուգակցված միավորներ ստեղծելու համար, որոնք հեշտ է փորձարկել, փոփոխել և թարմացնել: Այս սկզբունքը կարելի է ձևակերպել հետևյալ կերպ.

Վերին մակարդակի մոդուլները չպետք է կախված լինեն ավելի ցածր մակարդակի մոդուլներից: Երկուսն էլ պետք է կախված լինեն վերացականությունից:

Աբստրակցիան չպետք է կախված լինի մանրամասներից։ Մանրամասները պետք է կախված լինեն աբստրակցիաներից:

Սկզբունքը հասկանալու համար հաշվի առեք հետևյալ օրինակը.

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

Book դասը, որը ներկայացնում է գիրք, օգտագործում է ConsolePrinter դասը տպելու համար: Երբ սահմանվում է այսպես, Book դասը կախված է ConsolePrinter դասից: Ավելին, մենք հստակ սահմանել ենք, որ գիրք տպել հնարավոր է միայն կոնսոլում՝ օգտագործելով ConsolePrinter դասը: Այլ տարբերակներ, օրինակ՝ տպիչի ելք, ֆայլի ելք կամ գրաֆիկական ինտերֆեյսի որոշ տարրերի օգտագործում, այս դեպքում այս ամենը բացառված է: Գրքի տպագրության աբստրակցիան առանձնացված չէ ConsolePrinter դասի մանրամասներից: Այս ամենը կախվածության ինվերսիայի սկզբունքի խախտում է։

Այժմ եկեք փորձենք մեր դասերը համապատասխանեցնել կախվածության ինվերսիայի սկզբունքին՝ բաժանելով աբստրակցիաները ցածր մակարդակի իրականացումից.

Ինտերֆեյս IPprinter ( void Print (string text); ) class Book ( public string Text ( get; set; ) public IPprinter Printer ( get; set; ) public Book (IPprinter printer) ( this.Printer = printer; ) public void Print ( ) ( Printer.Print(Text); ) ) դաս ConsolePrinter. IPprinter ( public void Print(string text) ( Console.WriteLine ("Print to Console"); ) ) class HtmlPrinter: IPprinter ( public void Print(string text) ( Console.WriteLine ("Տպել html"); ) )

Այժմ գրքերի տպագրական աբստրակցիան առանձնացված է կոնկրետ իրականացումներից։ Արդյունքում և՛ Book դասը, և՛ ConsolePrinter դասը կախված են IPprinter աբստրակցիայից: Բացի այդ, այժմ մենք կարող ենք նաև ստեղծել IPprinter աբստրակցիայի լրացուցիչ ցածր մակարդակի իրականացումներ և դրանք դինամիկ կիրառել ծրագրում.

Գրքի գիրք = նոր Գիրք (new ConsolePrinter()); book.Print(); book.Printer = new HtmlPrinter(); book.Print();

Կախվածության ինվերսիան ծրագրավորման ամենակարևոր արտահայտություններից մեկն է։ Ռուսալեզու ինտերնետում այս բառապաշարի (սկզբունքի) նկարագրությունները զարմանալիորեն քիչ են: Ուստի որոշեցի փորձել նկարագրություն անել: Ես օրինակներ կանեմ Java-ում, այս պահին ինձ համար ավելի հեշտ է, չնայած կախվածության ինվերսիայի սկզբունքը կիրառելի է ցանկացած ծրագրավորման լեզվի համար:

Այս նկարագրությունը մշակվել է Վլադիմիր Մատվեևի հետ համատեղ՝ Java-ի ուսանողների հետ դասերին նախապատրաստվելու համար:

Այլ հոդվածներ այս շարքից.

Սկսենք «կախվածության» սահմանումից։ Ինչ է կախվածությունը: Եթե ​​ձեր կոդը ներսում օգտագործում է ինչ-որ դաս կամ բացահայտորեն կանչում է ինչ-որ դասի կամ ֆունկցիայի ստատիկ մեթոդ, սա կախվածություն է: Օրինակներով բացատրեմ.

A դասից ներքև SomeMethod() կոչվող մեթոդի ներսում բացահայտորեն ստեղծում է B դասի օբյեկտ և մուտք է գործում իր մեթոդը՝ someMethodOfB()

Հանրային A դաս ( void someMethod() (B b = new B(); b.someMethodOfB();))

Նմանապես, օրինակ, B դասը բացահայտորեն վերաբերում է System դասի ստատիկ դաշտերին և մեթոդներին.

Հանրային դաս B ( void someMethodOfB() ( System.out.println («Բարև աշխարհ»); )

Բոլոր այն դեպքերում, երբ ցանկացած դաս (տեսակ A) ինքն է ստեղծում որևէ դաս (տեսակ B) կամ բացահայտորեն մուտք է գործում ստատիկ դաշտեր կամ դասի անդամներ, սա կոչվում է. ուղիղկախվածություն. Նրանք. կարևոր է. եթե դասը իր ներսում աշխատում է իր ներսում մեկ այլ դասի հետ, սա կախվածություն է: Եթե ​​նա իր ներսում էլ է ստեղծում այս դասը, ապա սա ուղիղկախվածություն.

Ի՞նչ վատ բան կա ուղղակի կախվածության մեջ: Ուղղակի կախվածությունները վատ են, քանի որ դասը, որն ինքնուրույն է ստեղծում մեկ այլ դաս իր ներսում, «սերտորեն» կապված է այս դասի հետ: Նրանք. եթե հստակ գրված է, որ B = new B(); , ապա A դասը միշտ կաշխատի B դասի հետ և ոչ մի այլ դասի: Կամ եթե գրված է System.out.println("..."); ապա դասը միշտ դուրս կգա System.out և ոչ մի այլ տեղ:

Փոքր դասարանների համար կախվածությունը սարսափելի չէ: Նման ծածկագիրը կարող է լավ աշխատել: Բայց որոշ դեպքերում, որպեսզի ձեր A դասը համընդհանուր աշխատի տարբեր դասերի միջավայրում, նրան կարող են անհրաժեշտ լինել դասերի այլ իրականացումներ՝ կախվածություններ: Նրանք. Ձեզ անհրաժեշտ կլինի, օրինակ, ոչ թե B դաս, այլ նույն ինտերֆեյսով մեկ այլ դաս, կամ ոչ System.out, այլ, օրինակ, ելք դեպի լոգեր (օրինակ՝ log4j):

Ուղղակի կախվածությունը կարող է գրաֆիկորեն ցուցադրվել այսպես.

Նրանք. երբ ձեր կոդում A դաս եք ստեղծում. A a = new A(); իրականում ստեղծվում է ոչ թե մեկ A դաս, այլ կախյալ դասերի մի ամբողջ հիերարխիա, որի օրինակը վերը նշված նկարում է։ Այս հիերարխիան «կոշտ» է. առանց առանձին դասերի սկզբնական կոդը փոխելու, հիերարխիայի դասերից ոչ մեկը չի կարող փոխարինվել: Հետևաբար, A դասը նման իրականացման մեջ վատ հարմարվողական է փոփոխվող միջավայրին: Ամենայն հավանականությամբ, այն հնարավոր չի լինի օգտագործել ոչ մի կոդով, բացի այն կոնկրետից, որի համար գրել եք։

A դասը հատուկ կախվածություններից անջատելու համար կիրառեք կախվածության ներարկում. Ի՞նչ է կախվածության ներարկումը: Կոդում ցանկալի դասը բացահայտորեն ստեղծելու փոխարեն, կախվածությունները փոխանցվում են A դասին կոնստրուկտորի միջոցով.

Հանրային դաս A ( մասնավոր վերջնական B b; հանրային A(B b) ( this.b = b; ) public void someMethod() (b.someMethodOfB(); ) )

Դա. A դասը այժմ ստանում է իր կախվածությունը կոնստրուկտորի միջոցով: Այժմ A դասը ստեղծելու համար նախ պետք է ստեղծել դրա կախյալ դասը: Այս դեպքում դա B է:

B b = նոր B(); A a = նոր A(b); a.someMethod();

Եթե ​​նույն ընթացակարգը կրկնվում է բոլոր դասերի համար, այսինքն. փոխանցեք D դասի օրինակը B դասի կոնստրուկտորին, D դասի կոնստրուկտորին՝ նրա կախվածությունները E և F և այլն, ապա կստանաք ծածկագիր, որի բոլոր կախվածությունները ստեղծվում են հակառակ հերթականությամբ.

G g = նոր G (); H h = նոր H(); F f = նոր (g,h); E e = նոր E(); D d = նոր D(e,f); B b = նոր B(d); A a = նոր A(b); a.someMethod();

Գրաֆիկորեն սա կարող է ցուցադրվել այսպես.

Եթե ​​համեմատեք 2 նկար՝ վերևի նկարը ուղղակի կախվածությամբ և երկրորդ նկարը՝ կախվածության ներարկման հետ, ապա կտեսնեք, որ սլաքների ուղղությունը փոխվել է հակառակը: Այդ իսկ պատճառով բառակապակցությունը կոչվում է «կախվածության ինվերսիա»։ Այլ կերպ ասած, կախվածության ինվերսիան կայանում է նրանում, որ դասը ինքնուրույն չի ստեղծում կախվածություններ, այլ դրանք ստանում է ստեղծված ձևով կոնստրուկտորում (կամ այլ կերպ):

Ինչու է կախվածության շրջադարձը լավ: Կախվածության հակադարձման միջոցով դուք կարող եք փոխարինել դասի բոլոր կախվածությունները՝ առանց դրա ծածկագիրը փոխելու: Եվ սա նշանակում է, որ ձեր A դասը կարող է ճկուն կերպով կարգավորվել այլ ծրագրում օգտագործելու համար, քան այն, որի համար այն ի սկզբանե գրվել է: Դա. Կախվածության հակադարձման սկզբունքը (երբեմն կոչվում է կախվածության ներարկման սկզբունք) ճկուն, մոդուլային, բազմակի օգտագործման կոդ ստեղծելու բանալին է:

Կախվածության ներարկման թերությունը տեսանելի է նաև առաջին հայացքից. դասերի օբյեկտները, որոնք նախագծված են այս օրինաչափությամբ, դժվար է կառուցել: Հետևաբար, կախվածության ներարկումը (ինվերսիան) սովորաբար օգտագործվում է որոշակի գրադարանի հետ համատեղ, որը նախատեսված է այս առաջադրանքը հեշտացնելու համար: Օրինակ՝ Google Guice գրադարաններից մեկը։ Սմ. .

© 2022 skudelnica.ru -- Սեր, դավաճանություն, հոգեբանություն, ամուսնալուծություն, զգացմունքներ, վեճեր