JavaRush /Java Blogu /Random-AZ /Bahar. Dərs 2. IoC/DI praktikada
Umaralikhon
Səviyyə
Красноярск

Bahar. Dərs 2. IoC/DI praktikada

Qrupda dərc edilmişdir
Və beləliklə... Əvvəlki dərsdə biz IoC və DI-nin nəzəri hissəsini qısaca nəzərdən keçirdik. Layihəmiz üçün pom.xml konfiqurasiya faylını da quraşdırdıq. Bu gün proqramın əsas hissəsini yaratmağa başlayırıq. Əvvəlcə sizə IoC / DI olmadan bir proqram yaratmağı göstərəcəyəm. Və sonra biz birbaşa asılılıqları müstəqil şəkildə təqdim edən bir proqram yaradacağıq. Yəni kodun idarəsi çərçivənin əlinə keçir (ürpertici səslənir). Biz proqramı idarə edərkən təsəvvür edin ki, müəyyən bir şirkət var. Və şirkətin (hazırda) iki departamenti var: Java İnkişafı və İşə qəbul şöbəsi. “Java İnkişafı Departamentini” təsvir edən sinifin iki üsulu olsun: String getName() - işçinin adının qaytarılması, String getJob() - işçinin mövqeyinin qaytarılması. (Siyahı 1)
package org.example;

public class JavaDevelopment {

    public String getName(){
        return "Alexa";
    }

    public String getJob(){
        return "Middle Java developer";
    }
}
İşə qəbul departamentini təsvir edən sinifdə işçi qəbul edən giriş konstruktoru və işçilər haqqında məlumatı əks etdirən void displayInfo() metodu olsun. (Siyahı 2)
package org.example;

public class HiringDepartment {
    private JavaDevelopment javaDevelopment;

    public HiringDepartment(JavaDevelopment javaDevelopment) {
        this.javaDevelopment = javaDevelopment;
    }

    public void displayInfo() {
        System.out.println("Name: " + javaDevelopment.getName());
        System.out.println("Job: " + javaDevelopment.getJob());
    }
}
Main də var - bütün şöbələri idarə edən sinif. (Siyahı 3)
package org.example;

public class Main {
    public static void main(String ... args){
        JavaDevelopment javaDevelopment = new JavaDevelopment();
        HiringDepartment hiringDepartment = new HiringDepartment(javaDevelopment);

        hiringDepartment.displayInfo();
    }
}
Hələlik sabitlik. Main sinfini işə saldıqda aşağıdakı nəticəni alırıq:
Name: Alexa
Job: Middle Java developer
İndi təsəvvür edək ki, şirkət əla işləyir. Buna görə də, onlar fəaliyyət dairəsini genişləndirmək qərarına gəldilər və Python inkişaf şöbəsi açdılar. Və burada sual yaranır: Bu şöbəni proqram səviyyəsində necə təsvir etmək olar? Cavab: bu şöbəni təsvir etmək üçün lazım olan yerdə "kopyala və yapışdırmaq" lazımdır (yaxşı köhnə üsul🙃). Əvvəlcə "Pythonists" bölməsini təsvir edən sinfi yaradaq. (Siyahı 4)
package org.example;

public class PythonDevelopment {
    public String getName(){
        return "Mike";
    }

    public String getJob(){
        return "Middle Python developer";
    }
}
Və sonra onu HiringDepartment-ə köçürəcəyik. Və HiringDepartment bu şöbə haqqında heç nə demir. Buna görə də, siz PythonDevelopment sinifinin yeni obyekti və Python tərtibatçılarını qəbul edən konstruktor yaratmalı olacaqsınız. Siz həmçinin displayInfo() metodunu dəyişdirməli olacaqsınız ki, o, məlumatı düzgün göstərsin. (Siyahı 5)
package org.example;

public class HiringDepartment {
    private JavaDevelopment javaDevelopment;

    public HiringDepartment(JavaDevelopment javaDevelopment) {
        this.javaDevelopment = javaDevelopment;
    }


    //Тут создается отдел найма для Python - разработчиков
    private PythonDevelopment pythonDevelopment;

    public HiringDepartment(PythonDevelopment pythonDevelopment) {
        this.pythonDevelopment = pythonDevelopment;
    }

    //Тогда придется изменить метод displayInfo()
    public void displayInfo() {
        if(javaDevelopment != null) {
            System.out.println("Name: " + javaDevelopment.getName());
            System.out.println("Job: " + javaDevelopment.getJob());
        } else if (pythonDevelopment != null){
            System.out.println("Name: " + pythonDevelopment.getName());
            System.out.println("Job: " + pythonDevelopment.getJob());
        }
    }
}
Gördüyümüz kimi kodun həcmi iki dəfə, hətta daha çox artıb. Böyük miqdarda kodla onun oxunma qabiliyyəti azalır. Ən pisi isə odur ki, biz bütün obyektləri əl ilə yaradırıq və bir-birindən çox asılı olan siniflər edirik. Yaxşı, bununla razılaşdıq. Sadəcə bir şöbəni təsvir etdilər. Bundan heç nə itirməyəcəyik. Yaxşı, başqa şöbə əlavə etsək necə olacaq? İki olsa nə olar? Üç? Ancaq heç kim "mədən və otlaq" qadağan etmədi. Bahar.  Dərs 2. IoC / DI praktikada - 1 Bəli, heç kim “Min və otlaq”ı qadağan etməyib, amma bu, peşəkarlıq deyil. Tyzh proqramçıdır. Və burada DI-dən istifadə edə bilərsiniz. Yəni biz sinif səviyyəsində deyil, interfeys səviyyəsində işləyəcəyik. İndi obyektlərimizin vəziyyətləri interfeyslərdə saxlanılacaq. Beləliklə, siniflər arasında asılılıq minimal olacaqdır. Bunun üçün əvvəlcə işçini təsvir etmək üçün iki üsula malik İnkişaf interfeysini yaradırıq. (Siyahı 6)
package org.example;

public interface Development {
    String getName();
    String getJob();
}
İki sinif JavaDevelopment və PythonDevelopment bu interfeysdən həyata keçirsin (miras alsın) və String getName() və String getJob() metodlarını ləğv etsin. (Siyahı 7, 8)
package org.example;

public class JavaDevelopment implements Development {
    @Override
    public String getName(){
        return "Alexa";
    }

    @Override
    public String getJob(){
        return "Middle Java developer";
    }
}
package org.example;

public class PythonDevelopment implements Development {
    @Override
    public String getName(){
        return "Mike";
    }

    @Override
    public String getJob(){
        return "Middle Python developer";
    }
}
Sonra HiringDepartment sinfində siz sadəcə olaraq Development tipli interfeys obyektini təyin edə bilərsiniz və belə obyekti konstruktora da ötürə bilərsiniz. (Siyahı 9)
package org.example;

public class HiringDepartment {
    private Development development; //Определяем интерфейс

    //Конструктор принимает an object интерфейса
    public HiringDepartment(Development development){
        this.development = development;
    }

    public void displayInfo(){
        System.out.println("Name: " + development.getName());
        System.out.println("Job: " + development.getJob());
    }
}
Gördüyümüz kimi kodun miqdarı azalıb. Və ən əsası, asılılıqlar minimuma endirildi. Bu obyektlər üçün dəyərlər və asılılıqlar əslində necə həyata keçirilir? Asılılıq inyeksiyasının üç yolu var:
  • Konstruktordan istifadə etməklə
  • Ayarlayıcılardan istifadə
  • Avtomatik kabelləşdirmə (avtomatik bağlama)
Konstruktordan istifadə etməklə həyata keçirmə İndi konstruktordan istifadə etməklə həyata keçirmə haqqında danışaq. Siyahıya 9-a baxın. HiringDepartment sinifinin konstruktoru giriş kimi Development tipli obyekti gözləyir. Bu konstruktor vasitəsilə asılılıqları daxil etməyə çalışacağıq. Həm də qeyd etmək lazımdır ki, asılılıq enjeksiyonu sözdə Bahar qablarından istifadə etməklə həyata keçirilir. Bahar konteynerlərini konfiqurasiya etməyin üç yolu var:
  • XML fayllarından istifadə (köhnəlmiş metod)
  • Annotasiyalardan + XML fayllarından istifadə (Müasir üsul)
  • Java kodundan istifadə (müasir üsul)
İndi XML fayllarından istifadə edərək konfiqurasiyadan istifadə edirik. Bu metodun köhnəlmiş hesab edilməsinə baxmayaraq, bir çox layihələr hələ də bu şəkildə yazılır. Buna görə də bilmək lazımdır. Əvvəlcə resurslar qovluğunda xml faylı yaratmalısınız. Siz ona hər hansı bir ad verə bilərsiniz, lakin daha yaxşı mənalı bir ad verə bilərsiniz. Mən onu "applicationContext.xml" adlandırdım. Bahar.  Dərs 2. IoC / DI praktikada - 2 Bu faylda aşağıdakı kod parçasını yazacağıq (Siyahı 10):
<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="javaDeveloper" class="org.example.JavaDevelopment"/>
    <bean id="pythonDeveloper" class="org.example.PythonDevelopment"/>

    <bean id="hiringDepartment" class="org.example.HiringDepartment">
        <constructor-arg ref="javaDeveloper"/>
    </bean>

</beans>
İndi, qaydasında. Kodun ilk səkkiz sətri bizim üçün maraqlı deyil, onlar standartdır. Siz sadəcə onları kopyalaya bilərsiniz. <bean> </bean> teqi Yaz paxlasını təyin edir. Paxla, Spring konteyneri tərəfindən yaradılan və idarə olunan bir obyektdir. Sadə sözlə, Spring konteynerinin özü bizim üçün yeni sinif obyekti yaradır (məsələn: JavaDevelopment javaDevelopment = new JavaDevelopment();). Bu etiketin içərisində id və sinif atributları var. id paxlanın adını müəyyən edir. Bu id obyektə daxil olmaq üçün istifadə olunacaq. Java sinifindəki obyektin adına bərabərdir. class - paxlamızın (obyektimizin) bağlı olduğu sinfin adını müəyyən edir. Sinfin tam yolunu göstərməlisiniz. İşə qəbul şöbəsinə diqqət yetirin. Bu paxlanın içərisində başqa bir <constructor-arg ref="javaDeveloper"/> teqi var. Burada asılılıq inyeksiyası baş verir (bizim vəziyyətimizdə konstruktordan istifadə edərək inyeksiya). <constructor-arg> - Spring-ə bildirir ki, Spring konteyneri paxla atributunda müəyyən edilmiş sinif konstruktorunda asılılıqlar axtarmalıdır. Hansı obyektlə əlaqələndirilməli olduğu ref atributu ilə müəyyən edilir , <constructor-arg> teqinin içərisində. ref - əlaqə üçün paxlanın identifikatorunu göstərir. Əgər ref-də javaDeveloper əvəzinə id pythonDeveloper-ı təyin ediriksə, onda əlaqə PythonDevelopmen sinfi ilə baş verir. İndi biz Main sinfi təsvir etməliyik. Bu belə görünəcək: (Siyahı11)
package org.example;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String ... args){
        //Определяем контекст файл в котором содержатся прописанные нами бины
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //Получем бины, которые были определены в файле applicationContext.xml
        HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);

        hiringDepartment.displayInfo();

        context.close(); //Контекст всегда должен закрываться
    }
}
Burada nə var?
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Bu sətir Əsas sinfi paxlalarımızı təsvir edən .xml faylı ilə əlaqələndirir. Konstruktora verilən dəyər .xml faylının adına uyğun olmalıdır. (Bizim halda applicationContext.xml).
HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);
HiringDepartment sinifinin lobyasını (obyektini) əldə etmək istədiyimizi göstərir. Birinci arqument xml faylında yazdığımız lobya identifikatoruna işarə edir. İkinci arqument əlaqə qurmaq istədiyimiz sinfə işarə edir. Bu proses əks adlanır .
hiringDepartment.displayInfo();
 context.close(); //Контекст всегда должен закрываться
Burada biz asanlıqla HiringDepartment sinfinin metodunu əldə edirik. Qeyd edək ki, biz obyektləri əldə etmək üçün new açar sözündən istifadə etməmişik və JavaDevelopment və ya PythonDevelopment tipli asılı obyektləri heç bir yerdə müəyyən etməmişik. Onlar sadəcə applicationContext.xml faylında təsvir edilmişdir. Son sətirə də diqqət yetirin. Bağlamadan əvvəl həmişə konteksti bağlamalısınız. Əks halda, resurslar boşalmayacaq və yaddaş sızması və ya proqramın səhv işləməsi baş verə bilər. Suallarınız və ya təklifləriniz varsa, şərhlərdə yazın, mütləq cavablandıracağam. Diqqətiniz üçün təşəkkürlər. Linkdəki mənbə kodu GitHub Səbətim Kursun məzmunu Davam ediləcək...
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION