Asılılığın inversiya prinsipindən istifadə etməklə həyata keçirilir. Asılılığın İnversiya

ev / Mübahisə

Əslində bütün prinsiplər MƏKTƏK bir-biri ilə sıx bağlıdır və onların əsas məqsədi yüksək keyfiyyətli, genişlənə bilən proqram təminatı yaratmağa kömək etməkdir. Ancaq son prinsip MƏKTƏK həqiqətən onlara qarşı çıxır. Əvvəlcə bu prinsipin formuluna nəzər salaq. Belə ki, asılılığın inversiya prinsipi (Asılılığın inversiya prinsipi - DIP): “Abstraksiyalardan asılılıq. Konkret bir şeydən asılılıq yoxdur.. Bədnam proqram təminatı üzrə mütəxəssis Robert Martin də prinsipi vurğulayır DIP və onu sadəcə olaraq başqa prinsiplərə əməl etməyin nəticəsi kimi təqdim edir MƏKTƏK— açıq/qapalı prinsip və Liskov əvəzetmə prinsipi. Yada salaq ki, birincisi deyir ki, sinfi yeni dəyişikliklər etmək üçün dəyişdirmək olmaz, ikincisi isə irsiyyətlə məşğul olur və proqramın düzgün işləməsini pozmadan hansısa əsas növün törəmə növlərinin təhlükəsiz istifadəsini nəzərdə tutur. Robert Martin əvvəlcə bu prinsipi aşağıdakı kimi formalaşdırdı:

bir). Yuxarı səviyyə modulları aşağı səviyyəli modullardan asılı olmamalıdır. Hər iki səviyyədəki modullar abstraksiyalardan asılı olmalıdır.

2). Abstraksiyalar detallardan asılı olmamalıdır. Təfərrüatlar abstraksiyalardan asılı olmalıdır.

Yəni sinifləri onların konkret həyata keçirmələri deyil, abstraksiyalar baxımından inkişaf etdirmək lazımdır. Və prinsiplərə əməl etsəniz OCPLSP, onda bizim nail olacağımız şey məhz budur. Ona görə də dərsə bir az qayıdaq. Orada nümunə olaraq sinfi nəzərdən keçirdik bard, ən əvvəlində sinifə bərkidilmişdi Gitara, müəyyən bir musiqi alətini təmsil edən:

ictimai sinif Bard ( şəxsi Gitara gitara; ictimai Bard(Guitar gitara) ( this.guitar = guitar; ) public void play() ( guitar.play(); ) )

ictimai sinif Bard(

şəxsi gitara gitara;

ictimai bard (gitara gitara)

bu. gitara = gitara;

ictimai boşluq oyunu()

gitara. oynamaq();

Əgər bu sinfə başqa musiqi alətləri üçün dəstək əlavə etmək istəsək, o zaman bu sinfi birtəhər dəyişdirməli olardıq. Bu, prinsipin açıq şəkildə pozulmasıdır OCP. Və yəqin ki, siz artıq fikir vermişsiniz ki, bunlar da prinsipin pozulmasıdır DIP, çünki bizim vəziyyətimizdə abstraksiyamız detallardan asılı oldu. Sinifimizin daha da genişlənməsi baxımından bu heç də yaxşı deyil. Sinifimizin prinsip şərtlərinə cavab verməsi OCP sistemə interfeys əlavə etdik alət musiqi alətlərinin müəyyən növlərini təmsil edən xüsusi sinifləri həyata keçirən .

Fayl Alət.java:

İctimai interfeys Aləti (void play(); )

ictimai interfeys aləti(

voidplay();

Fayl Guitar.java:

sinif Gitara alətləri aləti( @Override public void play() ( System.out.println("Play Guitar!"); ) )

sinif Gitara alətləri Aləti(

@Qayda

ictimai boşluq oyunu()

Sistem. həyata. println("Gitara çal!");

Fayl lute.java:

ictimai sinif Lute Aləti həyata keçirir( @Override public void play() ( System.out.println("Play Lute!"); ) )

ictimai sinif Lute Aləti həyata keçirir(

@Qayda

ictimai boşluq oyunu()

Sistem. həyata. println("Lut çalın!");

Bundan sonra sinfi dəyişdik bard belə ki, lazım gələrsə, tətbiqləri tam olaraq ehtiyacımız olanlarla əvəz edə bilək. Bu, yaradılan sistemə əlavə çeviklik gətirir və onun birləşməsini azaldır (bir-birindən güclü sinif asılılığı).

ictimai sinif Bard ( şəxsi Alət aləti; ictimai Bard() ( ) ictimai void play() ( instrument.play(); ) ictimai void setInstrument(Alət aləti) ( this.instrument = alət; ) )

ictimai sinif Bard(

şəxsi alət aləti;

2 cavab

Yaxşı məqam - inversiya sözü bir qədər təəccüblüdür (çünki DIP tətbiq edildikdən sonra aşağı səviyyəli asılılıq modulu, görünür, indi daha yüksək səviyyəli zəng edən moduldan asılı deyil: ya zəng edən, ya da asılı olan şəxs əlavə abstraksiya vasitəsilə daha sərbəst birləşdirilir. ).

Soruşa bilərsiniz ki, mən niyə “inversiya” sözünü işlədirəm. Açığı, bunun səbəbi, strukturlaşdırılmış təhlil və dizayn kimi daha ənənəvi proqram təminatının inkişaf etdirilməsi üsullarının yüksək səviyyəli modulların aşağı səviyyəli modullardan asılı olduğu və abstraksiyaların detallardan asılı olduğu proqram strukturları yaratmağa meyllidir. Əslində, bu metodların məqsədlərindən biri yüksək səviyyəli modulların aşağı səviyyəli modullara necə zənglər etdiyini təsvir edən alt proqramların iyerarxiyasını müəyyən etməkdir.... Beləliklə, yaxşı tərtib edilmiş obyekt yönümlü proqramın asılılıq strukturu adətən ənənəvi prosessual metodların nəticəsi olan asılılıq strukturuna münasibətdə “ters çevrilmişdir”.

Bob dayının DIP-də yazdığı məqaləni oxuyarkən diqqət yetirilməli olan bir məqam da odur ki, C++ interfeysi yoxdur (və yazı zamanı, yoxdur), ona görə də C++ dilində bu abstraksiyaya nail olmaq adətən abstrakt/saf virtual baza sinfi vasitəsilə əldə edilir, halbuki Java-da və ya C# birləşməni boşaltmaq üçün abstraksiya adətən interfeysi asılılıqdan çıxarmaqla və daha yüksək səviyyəli modulları interfeysə bağlamaqdan ibarətdir.

Redaktə et Sadəcə aydınlaşdırmaq üçün:

"Bəzi yerdə mən də görürəm ki, buna asılılığın inversiyası deyilir"

İnversiya: Asılılıq idarəetməsini tətbiqdən konteynerə çevirin (Bahar kimi).

Asılılıq Enjeksiyonu:

Zavod nümunəsini yazmaq əvəzinə, obyekti birbaşa müştəri sinfinə yeritmək necədir. Beləliklə, gəlin müştəri sinfinə interfeysə müraciət edək və biz konkret növü müştəri sinfinə yeridə bilməliyik. Bununla müştəri sinfinin new açar sözündən istifadə etməsinə ehtiyac qalmır və konkret siniflərdən tamamilə ayrılır.

Nəzarətin ters çevrilməsi (IoC) haqqında nə demək olar?

Ənənəvi proqramlaşdırmada biznes məntiqinin axını bir-birinə statik olaraq təyin edilmiş obyektlər tərəfindən müəyyən edilir. İdarəetmənin tərsinə çevrilməsi ilə axın assembler tərəfindən yaradılan və abstraksiyalar vasitəsilə müəyyən edilmiş obyekt qarşılıqlı əlaqəsi ilə mümkün olan obyekt qrafikindən asılıdır. Birləşmə prosesi asılılıq inyeksiyası vasitəsilə əldə edilir, baxmayaraq ki, bəziləri xidmət lokatorundan istifadənin idarəetmənin inversiyasını da təmin etdiyini iddia edir.

Nəzarətin dizayn bələdçisi kimi çevrilməsi aşağıdakı məqsədlərə xidmət edir:

  • Müəyyən bir tapşırığın icrasının icradan ayrılması var.
  • Hər bir modul nə üçün nəzərdə tutulduğuna diqqət yetirə bilər.
  • Modullar digər sistemlərin nə etdiyi barədə heç bir fərziyyə irəli sürmür, lakin onların müqavilələrinə əsaslanır.
  • Modulların dəyişdirilməsi digər modullara təsir göstərmir.

Ətraflı məlumat üçün baxın.

Son yeniləmə: 03/11/2016

Asılılığın inversiya prinsipi(Asılılığın İnversiya Prinsipi) sınaqdan keçirmək, dəyişdirmək və yeniləmək asan olan, sərbəst şəkildə birləşdirilmiş obyektlər yaratmaq üçün istifadə olunur. Bu prinsipi aşağıdakı kimi formalaşdırmaq olar:

Üst səviyyə modulları aşağı səviyyəli modullardan asılı olmamalıdır. Hər ikisi abstraksiyalardan asılı olmalıdır.

Abstraksiyalar detallardan asılı olmamalıdır. Təfərrüatlar abstraksiyalardan asılı olmalıdır.

Prinsipi başa düşmək üçün aşağıdakı nümunəyə nəzər salın:

Sinif Kitabı ( ictimai sətir Mətn ( almaq; təyin; ) ictimai ConsolePrinter Printer ( almaq; set; ) ictimai void Print() ( Printer.Print(Mətn); ) ) sinif ConsolePrinter ( ictimai etibarsız Çap(string mətn) ( Console.WriteLine (mətn); ))

Kitabı təmsil edən Book sinfi çap etmək üçün ConsolePrinter sinfindən istifadə edir. Bu şəkildə müəyyən edildikdə, Book sinfi ConsolePrinter sinfindən asılıdır. Üstəlik, kitabın çapının yalnız ConsolePrinter sinfindən istifadə edərək konsolda mümkün olduğunu qəti şəkildə müəyyən etdik. Digər variantlar, məsələn, printerə çıxış, fayla çıxış və ya qrafik interfeysin bəzi elementlərindən istifadə - bütün bunlar bu halda istisna olunur. Kitab çapı abstraksiya ConsolePrinter sinfinin detallarından ayrı deyil. Bütün bunlar asılılığın inversiya prinsipinin pozulmasıdır.

İndi abstraksiyaları aşağı səviyyəli icradan ayıraraq siniflərimizi asılılığın inversiya prinsipinə uyğunlaşdırmağa çalışaq:

İnterfeys IPrinter ( void Print(string text); ) class Book ( public string Text ( get; set; ) public IPrinter Printer ( get; set; ) public Book(IPrinter printer) ( this.Printer = printer; ) public void Print( ) ( Printer.Print(Mətn); ) ) sinif ConsolePrinter: IPrinter ( public void Print(string text) ( Console.WriteLine("Print to Console"); ) ) class HtmlPrinter: IPrinter ( public void Print(string text) ( Console.WriteLine("html-də çap et"); ) )

İndi kitab çapı abstraksiya konkret tətbiqlərdən ayrılıb. Nəticədə həm Book sinfi, həm də ConsolePrinter sinfi IPrinter abstraksiyasından asılıdır. Bundan əlavə, indi biz IPrinter abstraksiyasının əlavə aşağı səviyyəli tətbiqlərini də yarada və onları proqramda dinamik şəkildə tətbiq edə bilərik:

Kitab kitabı = yeni Kitab (yeni ConsolePrinter()); kitab.Çap(); kitab.Printer = yeni HtmlPrinter(); kitab.Çap();

Dependency inversion ən vacib proqramlaşdırma deyimlərindən biridir. Rusdilli İnternetdə bu idiomun (prinsipin) təsviri təəccüblü dərəcədə azdır. Buna görə də təsvir etməyə cəhd etmək qərarına gəldim. Mən Java-da nümunələr edəcəyəm, bu anda mənim üçün daha asandır, baxmayaraq ki, asılılığın inversiya prinsipi istənilən proqramlaşdırma dilinə tətbiq olunur.

Bu təsvir Vladimir Matveev ilə birlikdə Java tələbələri ilə dərslərə hazırlıq zamanı hazırlanmışdır.

Bu seriyadan digər məqalələr:

“Asılılıq” anlayışından başlayaq. Asılılıq nədir? Əgər kodunuz daxili olaraq hansısa sinifdən istifadə edirsə və ya hansısa sinfin və ya funksiyanın statik metodunu açıq şəkildə çağırırsa, bu, asılılıqdır. İcazə verin misallarla izah edim:

A sinfindən aşağıda someMethod() adlı metod daxilində B sinifinin obyektini açıq şəkildə yaradır və onun someMethodOfB() metoduna daxil olur.

İctimai sinif A ( void someMethod() ( B b = new B(); b.someMethodOfB(); ) )

Eynilə, məsələn, B sinfi açıq şəkildə Sistem sinfinin statik sahələrinə və metodlarına istinad edir:

İctimai sinif B ( void someMethodOfB() ( System.out.println("Salam dünya"); ) )

Hər hansı bir sinfin (tip A) özü hər hansı bir sinfi (tip B) yaratdığı və ya statik sahələrə və ya sinif üzvlərinə açıq şəkildə daxil olduğu bütün hallarda buna deyilir. düz asılılıq. Bunlar. vacibdir: əgər öz daxilindəki sinif öz daxilində başqa bir siniflə işləyirsə, bu, asılılıqdır. Bu təbəqəni də öz daxilində yaradırsa, bu düz asılılıq.

Birbaşa asılılıqlarda səhv nədir? Birbaşa asılılıqlar pisdir, çünki müstəqil olaraq öz daxilində başqa bir sinif yaradan sinif bu sinfə "sıx" bağlıdır. Bunlar. açıq şəkildə B = new B(); , onda A sinfi həmişə B sinfi ilə işləyəcək və başqa sinif yoxdur. Və ya System.out.println("..."); sonra sinif həmişə System.out-a çıxış edəcək və başqa heç bir yerdə.

Kiçik siniflər üçün asılılıqlar qorxunc deyil. Belə kod yaxşı işləyə bilər. Ancaq bəzi hallarda, A sinifinizin müxtəlif siniflər mühitində universal işləməsi üçün ona asılılıq siniflərinin başqa tətbiqləri lazım ola bilər. Bunlar. sizə, məsələn, B sinfinə deyil, eyni interfeysə malik başqa bir sinifə ehtiyacınız olacaq və ya System.out deyil, lakin, məsələn, loggerə çıxış (məsələn, log4j).

Birbaşa asılılıq qrafik olaraq bu şəkildə göstərilə bilər:

Bunlar. kodunuzda A sinfi yaratdığınız zaman: A a = new A(); əslində bir sinif A deyil, yuxarıdakı şəkildəki nümunə olan asılı siniflərin bütöv bir iyerarxiyası yaradılır. Bu iyerarxiya “sərtdir”: ayrı-ayrı siniflərin mənbə kodunu dəyişmədən iyerarxiyadakı siniflərin heç birini əvəz etmək olmaz. Buna görə də, belə bir tətbiqdə A sinfi dəyişən mühitə zəif uyğunlaşır. Çox güman ki, onu yazdığınız konkret koddan başqa heç bir kodda istifadə etmək mümkün olmayacaq.

A sinfini xüsusi asılılıqlardan ayırmaq üçün müraciət edin asılılıq inyeksiyası. Asılılıq inyeksiyası nədir? Kodda açıq şəkildə istədiyiniz sinfi yaratmaq əvəzinə, asılılıqlar konstruktor vasitəsilə A sinfinə ötürülür:

İctimai sinif A ( özəl final B b; ictimai A(B b) ( this.b = b; ) ictimai etibarsız someMethod() ( b.someMethodOfB(); ) )

Bu. A sinfi indi öz asılılığını konstruktor vasitəsilə əldə edir. İndi A sinfini yaratmaq üçün ilk növbədə onun asılı sinfini yaratmalısınız. Bu halda, B:

B b = yeni B(); A a = yeni A(b); a.someMethod();

Eyni prosedur bütün siniflər üçün təkrarlanırsa, yəni. D sinifinin nümunəsini B sinifinin konstruktoruna, D sinifinin konstruktoruna — onun E və F asılılıqları və s. ötürsəniz, bütün asılılıqları tərs qaydada yaradılmış kodu alacaqsınız:

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

Qrafik olaraq bu belə göstərilə bilər:

2 şəkli müqayisə etsəniz - yuxarıdakı birbaşa asılılıqları olan şəkil və asılılıq inyeksiyası ilə ikinci şəkil - oxların istiqamətinin əksinə dəyişdiyini görə bilərsiniz. Bu səbəbdən idiom "asılılıq inversiya" adlanır. Başqa sözlə, asılılığın inversiyası ondan ibarətdir ki, sinif öz-özünə asılılıq yaratmır, onları konstruktorda (yaxud başqa şəkildə) yaradılmış formada qəbul edir.

Asılılığın çevrilməsi niyə yaxşıdır? Asılılığın inversiyası ilə siz onun kodunu dəyişmədən sinifdəki bütün asılılıqları əvəz edə bilərsiniz. Və bu o deməkdir ki, A sinifiniz ilkin olaraq yazıldığı proqramdan başqa proqramda istifadə üçün çevik şəkildə konfiqurasiya edilə bilər. Bu. Dependency Inversion Prinsip (bəzən Asılılıq Injection Prinsiple adlanır) çevik, modul, təkrar istifadə edilə bilən kodun yaradılması üçün açardır.

Asılılıq inyeksiyasının dezavantajı da ilk baxışdan görünür - bu nümunədən istifadə edərək dizayn edilmiş siniflərin obyektlərinin qurulması çox zəhmətlidir. Buna görə də, asılılıq inyeksiyası (inversiya) adətən bu işi asanlaşdırmaq üçün nəzərdə tutulmuş bəzi kitabxana ilə birlikdə istifadə olunur. Məsələn, Google Guice kitabxanalarından biri. Sm. .

© 2022 skudelnica.ru -- Sevgi, xəyanət, psixologiya, boşanma, hisslər, mübahisələr