JavaRush /จาวาบล็อก /Random-TH /ฤดูใบไม้ผลิ. บทที่ 2. IoC/DI ในทางปฏิบัติ
Umaralikhon
ระดับ
Красноярск

ฤดูใบไม้ผลิ. บทที่ 2. IoC/DI ในทางปฏิบัติ

เผยแพร่ในกลุ่ม
ดังนั้น... ใน บทเรียน ที่แล้วเราได้ทบทวนส่วนทางทฤษฎีของ IoC และ DI โดยย่อ เรายังตั้งค่าไฟล์คอนฟิกูเรชัน pom.xml สำหรับโปรเจ็กต์ของเราด้วย วันนี้เราเริ่มสร้างส่วนหลักของโปรแกรม ก่อนอื่น ฉันจะแสดงวิธีสร้างโปรแกรมที่ไม่มี IoC / DI จากนั้นเราจะสร้างโปรแกรมที่แนะนำการพึ่งพาอย่างอิสระโดยตรง นั่นคือการควบคุมโค้ดจะส่งผ่านไปยังมือของเฟรมเวิร์ก (ฟังดูน่าขนลุก) ขณะที่เรากำลังจัดการโปรแกรม ลองจินตนาการว่ามีบริษัทแห่งหนึ่ง และบริษัท (ปัจจุบัน) มีสองแผนก: แผนก Java Development และ Hiring ให้ชั้นเรียนที่อธิบาย "Java Development Department" มีสองวิธี: 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();
    }
}
ความมั่นคงในตอนนี้. เมื่อเรารันคลาส Main เราจะได้ผลลัพธ์ดังนี้:
Name: Alexa
Job: Middle Java developer
ตอนนี้ลองจินตนาการว่าบริษัทกำลังไปได้สวย ดังนั้นพวกเขาจึงตัดสินใจขยายขอบเขตกิจกรรมและเปิดแผนกพัฒนา Python และนี่คือคำถามที่เกิดขึ้น: จะอธิบายแผนกนี้ในระดับโปรแกรมได้อย่างไร? คำตอบ: คุณต้อง “คัดลอกและวาง” ทุกที่ที่คุณต้องการอธิบายแผนกนี้ (วิธีเก่าที่ดี🙃) ขั้นแรก เรามาสร้างคลาสขึ้นมาซึ่งจะอธิบายแผนก "Pythonists" (รายการ 4)
package org.example;

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

    public String getJob(){
        return "Middle Python developer";
    }
}
จากนั้นเราจะโอนไปที่แผนกการจ้างงาน และแผนกการจ้างงานไม่ได้พูดอะไรเกี่ยวกับแผนกนี้เลย ดังนั้น คุณจะต้องสร้างอ็อบเจ็กต์ใหม่ของคลาส 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());
        }
    }
}
ดังที่เราเห็น จำนวนโค้ดเพิ่มขึ้นเป็นสองเท่าหรือมากกว่านั้น เมื่อมีโค้ดจำนวนมาก ความสามารถในการอ่านจะลดลง และสิ่งที่แย่ที่สุดคือเราสร้างออบเจ็กต์ทั้งหมดด้วยตนเอง และสร้างคลาสที่ต้องพึ่งพาซึ่งกันและกันในระดับสูง โอเค เราเห็นด้วยกับเรื่องนี้ พวกเขาอธิบายเพียงแผนกเดียว เราจะไม่สูญเสียสิ่งใดจากสิ่งนี้ แล้วถ้าเราเพิ่มแผนกอื่นล่ะ? แล้วถ้ามีสองคนล่ะ? สาม? แต่ไม่มีใครห้าม “การขุดและการแทะเล็มหญ้า” ฤดูใบไม้ผลิ.  บทที่ 2. IoC / DI ในทางปฏิบัติ - 1 ใช่ ไม่มีใครห้าม “เหมืองและทุ่งหญ้า” แต่นั่นไม่ใช่มืออาชีพ Tyzh เป็นโปรแกรมเมอร์ และที่นี่คุณสามารถใช้ 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());
    }
}
ดังที่เราเห็นจำนวนโค้ดลดลง และที่สำคัญที่สุด การพึ่งพาอาศัยกันลดลง ค่านิยมและการพึ่งพาถูกนำไปใช้กับวัตถุเหล่านี้จริง ๆ อย่างไร? มีสามวิธีในการฉีดการพึ่งพา:
  • การใช้ตัวสร้าง
  • การใช้เซ็ตเตอร์
  • การเดินสายอัตโนมัติ (การผูกอัตโนมัติ)
การนำไปใช้งานโดยใช้ Constructor ตอนนี้เรามาพูดถึงการใช้งานโดยใช้ Constructor กันดีกว่า ดูที่รายการ 9 ตัวสร้างของคลาส HiringDepartment คาดว่าอ็อบเจ็กต์ประเภท Development เป็นอินพุต เราจะพยายามฉีดการพึ่งพาผ่านตัวสร้างนี้ นอกจากนี้ยังเป็นที่น่าสังเกตว่าการฉีดการพึ่งพานั้นดำเนินการโดยใช้สิ่งที่เรียกว่า Spring Container มีสามวิธีในการกำหนดค่า Spring Container:
  • การใช้ไฟล์ XML (วิธีที่ล้าสมัย)
  • การใช้คำอธิบายประกอบ + ไฟล์ XML (สมัยใหม่)
  • การใช้โค้ด Java (วิธีสมัยใหม่)
ขณะนี้เรากำลังใช้การกำหนดค่าโดยใช้ไฟล์ XML แม้ว่าวิธีนี้จะถือว่าล้าสมัย แต่หลายโครงการยังคงเขียนในลักษณะนี้ ดังนั้นคุณจำเป็นต้องรู้ ขั้นแรก คุณต้องสร้างไฟล์ xml ในโฟลเดอร์ทรัพยากร คุณสามารถตั้งชื่ออะไรก็ได้ แต่ควรเป็นชื่อที่มีความหมาย ฉันเรียกมันว่า "applicationContext.xml" ฤดูใบไม้ผลิ.  บทที่ 2. IoC / DI ในทางปฏิบัติ - 2 ในไฟล์นี้เราจะเขียนโค้ดต่อไปนี้ (รายการ 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 bean beanเป็นวัตถุที่สร้างและจัดการโดยคอนเทนเนอร์ Spring พูดง่ายๆ ก็คือ Spring Container เองก็สร้างคลาสอ็อบเจ็กต์ใหม่สำหรับเรา (เช่น JavaDevelopment javaDevelopment = new JavaDevelopment();) ภายในแท็กนี้มีแอตทริบิวต์ id และ class idระบุชื่อของถั่ว รหัสนี้จะใช้เพื่อเข้าถึงวัตถุ มันเทียบเท่ากับชื่อของวัตถุในคลาส Java class - กำหนดชื่อของคลาสที่ bean (วัตถุ) ของเราผูกไว้ คุณต้องระบุเส้นทางแบบเต็มไปยังชั้นเรียน ให้ความสนใจกับการจ้างงานแผนกถั่ว ภายใน bean นี้มีแท็ก <constructor-arg ref="javaDeveloper"/> อีกแท็กหนึ่ง นี่คือจุดที่การพึ่งพาการฉีดเกิดขึ้น (ในกรณีของเรา การฉีดโดยใช้ตัวสร้าง) <constructor-arg> - บอก Spring ว่า Spring Container ควรมองหาการพึ่งพาในตัวสร้างคลาสที่กำหนดไว้ในแอตทริบิวต์ bean และวัตถุใดที่ต้องเชื่อมโยงกับจะถูกกำหนดโดย แอตทริบิวต์ refภายในแท็ก <constructor-arg> ref - ระบุ id ของ bean ที่จะติดต่อ หากในการอ้างอิงแทนที่จะเป็น javaDeveloper เราระบุ id pythonDeveloper การเชื่อมต่อจะเกิดขึ้นกับคลาส PythonDevelopmen ตอนนี้เราจำเป็นต้องอธิบายคลาสหลัก จะมีลักษณะดังนี้: (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");
บรรทัดนี้เชื่อมโยงคลาส Main ไปยังไฟล์ .xml ที่อธิบายถั่วของเรา ค่าที่ส่งไปยังตัวสร้างจะต้องตรงกับชื่อของไฟล์ .xml (ในกรณีของเรา applicationContext.xml)
HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);
บ่งชี้ว่าเราต้องการรับ bean (วัตถุ) ของคลาส HiringDepartment อาร์กิวเมนต์แรกชี้ไปที่ bean id ที่เราเขียนไว้ในไฟล์ xml อาร์กิวเมนต์ที่สองชี้ไปที่คลาสที่เราต้องการติดต่อ กระบวนการนี้เรียกว่าการ สะท้อน
hiringDepartment.displayInfo();
 context.close(); //Контекст всегда должен закрываться
ที่นี่เราเข้าใจวิธีการของคลาส HiringDepartment อย่างง่ายดาย โปรดทราบว่าเราไม่ได้ใช้คีย์เวิร์ดใหม่เพื่อรับอ็อบเจ็กต์ และเราไม่ได้กำหนดอ็อบเจ็กต์ที่ต้องพึ่งพาประเภท JavaDevelopment หรือ PythonDevelopment ทุกที่ มีการอธิบายไว้อย่างง่ายๆ ในไฟล์ applicationContext.xml ให้ความสนใจกับบรรทัดสุดท้ายด้วย คุณควรปิดบริบทก่อนที่จะปิดเครื่องเสมอ มิฉะนั้น ทรัพยากรจะไม่ถูกปล่อย และอาจเกิดหน่วยความจำรั่วหรือการทำงานของโปรแกรมไม่ถูกต้อง หากคุณมีคำถามหรือข้อเสนอแนะเขียนความคิดเห็นฉันจะตอบอย่างแน่นอน ขอบคุณสำหรับความสนใจ ซอร์สโค้ดที่ลิงก์เนื้อหาหลักสูตร My GitHub Cart มีต่อ...
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION