JavaRush /Java блогы /Random-KK /Көктем. 2-сабақ. IoC/DI тәжірибеде
Umaralikhon
Деңгей
Красноярск

Көктем. 2-сабақ. IoC/DI тәжірибеде

Топта жарияланған
Және де... Өткен сабақта IoC және DI теориялық бөлігін қысқаша қарастырдық. Сондай-ақ жобамыз үшін pom.xml конфигурация файлын орнаттық. Бүгін біз бағдарламаның негізгі бөлігін құруға кірісеміз. Біріншіден, мен IoC / DI жоқ бағдарламаны қалай жасау керектігін көрсетемін. Содан кейін біз тәуелділіктерді дербес енгізетін бағдарламаны тікелей жасаймыз. Яғни, codeты басқару рамканың қолына өтеді (қорқынышты естіледі). Біз бағдарламаны басқарып жатқанда, белгілі бір компания бар деп елестетіңіз. Ал компанияда (әзірше) екі бөлім бар: Java әзірлеу және жалдау бөлімі. «Java әзірлеу бөлімін» сипаттайтын сыныпта екі әдіс болсын: String getName() - қызметкердің атын қайтару, String getJob() - қызметкердің орнын қайтарады. (1-тізім)
package org.example;

public class JavaDevelopment {

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

    public String getJob(){
        return "Middle Java developer";
    }
}
Жалдау бөлімін сипаттайтын сыныпта қызметкерді қабылдайтын енгізу конструкторы және қызметкерлер туралы ақпаратты көрсететін void displayInfo() әдісі болсын. (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 - барлық бөлімдерді басқаратын сынып бар. (3-тізім)
package org.example;

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

        hiringDepartment.displayInfo();
    }
}
Әзірге тұрақтылық. Негізгі классты іске қосқан кезде біз келесі нәтиже аламыз:
Name: Alexa
Job: Middle Java developer
Енді компания керемет жұмыс істеп жатыр деп елестетейік. Сондықтан олар өз қызмет аясын кеңейтуді ұйғарып, Python әзірлеу бөлімін ашты. Осы жерде сұрақ туындайды: Бағдарлама деңгейінде бұл бөлімді қалай сипаттауға болады? Жауап: осы бөлімді сипаттау үшін қажет жерде «көшіру және қою» керек (ескі әдіс🙃). Алдымен, «Питонистер» бөлімін сипаттайтын сыныптың өзін жасайық. (4-тізім)
package org.example;

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

    public String getJob(){
        return "Middle Python developer";
    }
}
Содан кейін біз оны жалдау департаментіне береміз. Ал HiringDepartment бұл бөлім туралы ештеңе айтпайды. Сондықтан сізге PythonDevelopment класының жаңа нысанын және Python әзірлеушілерін қабылдайтын конструкторды жасау керек болады. Сондай-ақ, ақпаратты дұрыс көрсету үшін displayInfo() әдісін өзгертуге тура келеді. (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());
        }
    }
}
Көріп отырғанымыздай, code көлемі екі есе өсті, тіпті одан да көп. Кодтың үлкен көлемімен оның оқылу мүмкіндігі төмендейді. Ең сорақысы, біз барлық нысандарды қолмен жасаймыз және бір-біріне өте тәуелді сыныптар жасаймыз. Жарайды, біз мұнымен келістік. Олар жай ғана бір бөлімді сипаттады. Бұдан біз ештеңе жоғалтпаймыз. Ал, басқа бөлімді қоссақ ше? Екі болса ше? Үш? Бірақ «кен өндіру мен мал жаюға» ешкім тыйым салған жоқ. Көктем.  2-сабақ. Практикадағы IoC/DI – 1 Иә, «Кен мен жайылымға» ешкім тыйым салған жоқ, бірақ бұл кәсіби емес. Тыж – бағдарламашы. Мұнда сіз DI пайдалана аласыз. Яғни, біз сынып деңгейінде емес, интерфейс деңгейінде жұмыс істейтін боламыз. Енді біздің нысандардың күйлері интерфейстерде сақталады. Осылайша, сыныптар арасындағы тәуелділік минималды болады. Ол үшін алдымен қызметкерді сипаттаудың екі әдісі бар әзірлеу интерфейсін жасаймыз. (6-тізім)
package org.example;

public interface Development {
    String getName();
    String getJob();
}
Содан кейін JavaDevelopment және PythonDevelopment екі класына осы интерфейстен іске асыруға (мұра алуға) және String getName() және String getJob() әдістерін қайта анықтауға рұқсат етіңіз. (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";
    }
}
Содан кейін HiringDepartment сыныбында сіз жай ғана Development типті интерфейс нысанын анықтай аласыз және сондай-ақ мұндай нысанды конструкторға бере аласыз. (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());
    }
}
Көріп отырғанымыздай, code саны азайды. Ең бастысы, тәуелділік барынша азайтылды. Бұл нысандар үшін мәндер мен тәуелділіктер қалай жүзеге асырылады? Тәуелділік инъекциясын жасаудың үш жолы бар:
  • Конструкторды пайдалану
  • Параметрлерді пайдалану
  • Автоматты сымдау (автоматты байланыстыру)
Конструктор көмегімен іске асыру Енді конструкторды пайдаланып жүзеге асыру туралы сөйлесейік. Listing 9-ды қараңыз. HiringDepartment сыныбының конструкторы әзірлеу түріндегі нысанды енгізу ретінде күтеді. Біз осы конструктор арқылы тәуелділіктерді енгізуге тырысамыз. Сондай-ақ, тәуелділік инъекциясы көктемгі контейнерлер деп аталатындар арқылы орындалатынын атап өткен жөн. Spring контейнерлерін конфигурациялаудың үш жолы бар:
  • XML файлдарын пайдалану (ескірген әдіс)
  • Аннотацияларды + XML файлдарын пайдалану (заманауи әдіс)
  • Java codeын пайдалану (заманауи әдіс)
Біз қазір конфигурацияны XML файлдары арқылы пайдаланып жатырмыз. Бұл әдіс ескірген деп саналғанымен, көптеген жобалар әлі де осылай жазылады. Сондықтан сіз білуіңіз керек. Алдымен ресурстар қалтасында xml файлын жасау керек. Сіз оған кез келген атау бере аласыз, бірақ жақсырақ мағыналы. Мен оны "applicationContext.xml" деп атадым. Көктем.  2-сабақ. Практикадағы IoC/DI – 2 Бұл файлға біз келесі code бөлігін жазамыз (Листинг 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>
Енді, ретімен. Кодтың алғашқы сегіз жолы бізге қызық емес, олар әдепкі. Сіз оларды жай ғана көшіре аласыз. <bean> </bean> тегі көктемгі бұршақты анықтайды. Бұршақ - Spring контейнері арқылы жасалған және басқарылатын нысан. Қарапайым сөзбен айтқанда, Spring контейнерінің өзі біз үшін жаңа класс нысанын жасайды (мысалы: JavaDevelopment javaDevelopment = new JavaDevelopment();). Бұл тегтің ішінде id және класс атрибуттары бар. id бұршақтың атын көрсетеді. Бұл идентификатор нысанға қол жеткізу үшін пайдаланылады. Ол Java класындағы нысанның атына тең. класс - біздің бұршамыз (нысан) байланыстырылған сыныптың атын анықтайды. Сіз сыныпқа толық жолды көрсетуіңіз керек. Жұмысқа қабылдау бөліміне назар аударыңыз. Бұл бұршақтың ішінде басқа <constructor-arg ref="javaDeveloper"/> тегі бар. Дәл осы жерде тәуелділік инъекциясы орын алады (біздің жағдайда конструктор арқылы инъекция). <constructor-arg> - Spring-ке Spring контейнері бұршақ атрибутында анықталған класс конструкторында тәуелділіктерді іздеу керек екенін айтады. Қай нысанмен байланыстыру керектігі ref атрибуты арқылы анықталады , <constructor-arg> тегінде. ref - байланысатын бұршақтың идентификаторын көрсетеді. Егер javaDeveloper орнына ref ішінде pythonDeveloper идентификаторын көрсетсек, онда байланыс PythonDevelopmen сыныбында болады. Енді біз Main классты сипаттауымыз керек. Ол келесідей болады: (Listing11)
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(); //Контекст всегда должен закрываться
    }
}
Мұнда не бар?
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Бұл жол Негізгі сыныпты бұршақтарымызды сипаттайтын .xml файлына байланыстырады. Конструкторға берілген мән .xml файлының атына сәйкес болуы керек. (Біздің жағдайда applicationContext.xml).
HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);
HiringDepartment сыныбының бұршағын (нысанын) алғымыз келетінін көрсетеді. Бірінші аргумент xml файлында жазған бұршақ идентификаторын көрсетеді. Екінші аргумент біз хабарласқымыз келетін сыныпты көрсетеді. Бұл процесс рефлексия деп аталады .
hiringDepartment.displayInfo();
 context.close(); //Контекст всегда должен закрываться
Мұнда біз HiringDepartment класының әдісін оңай аламыз. Нысандарды алу үшін new кілт сөзін пайдаланбағанымызды және JavaDevelopment немесе PythonDevelopment түріндегі тәуелді нысандарды еш жерде анықтамағанымызды ескеріңіз. Олар applicationContext.xml файлында жай сипатталған. Сондай-ақ соңғы жолға назар аударыңыз. Өшіру алдында әрқашан контекстті жабу керек. Әйтпесе, ресурстар босатылмайды және жадтың ағуы немесе бағдарламаның дұрыс жұмыс істемеуі мүмкін. Егер сізде сұрақтар немесе ұсыныстар болса, түсініктемелерде жазыңыз, мен міндетті түрде жауап беремін. Назар аударғаныңызға рақмет. Менің GitHub арбамдағы сілтемедегі бастапқы code Курс мазмұны Жалғасы бар...
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION