JavaRush /Java Blog /Random-ID /Musim semi. Pelajaran 2. IoC/DI dalam praktiknya
Umaralikhon
Level 3
Красноярск

Musim semi. Pelajaran 2. IoC/DI dalam praktiknya

Dipublikasikan di grup Random-ID
Jadi... Pada pelajaran sebelumnya kita meninjau secara singkat bagian teoretis dari IoC dan DI. Kami juga menyiapkan file konfigurasi pom.xml untuk proyek kami. Hari ini kita mulai membuat bagian utama dari program ini. Pertama, saya akan menunjukkan cara membuat program tanpa IoC/DI. Dan kemudian kita akan langsung membuat program yang secara mandiri memperkenalkan dependensi. Artinya, kendali kode berpindah ke tangan kerangka kerja (terdengar menyeramkan). Saat kita mengelola program, bayangkan ada perusahaan tertentu. Dan perusahaan (untuk saat ini) memiliki dua departemen: Departemen Pengembangan Java dan Perekrutan. Biarkan kelas yang mendeskripsikan "Departemen Pengembangan Java" memiliki dua metode: String getName() - mengembalikan nama karyawan, String getJob() - mengembalikan posisi karyawan. (Daftar 1)
package org.example;

public class JavaDevelopment {

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

    public String getJob(){
        return "Middle Java developer";
    }
}
Biarkan kelas yang mendeskripsikan departemen perekrutan memiliki konstruktor masukan yang menerima karyawan, dan metode void displayInfo() yang menampilkan informasi tentang karyawan. (Daftar 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());
    }
}
Ada juga Utama - kelas yang mengelola semua departemen. (Daftar 3)
package org.example;

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

        hiringDepartment.displayInfo();
    }
}
Stabilitas untuk saat ini. Ketika kita menjalankan kelas Utama kita mendapatkan hasil sebagai berikut:
Name: Alexa
Job: Middle Java developer
Sekarang mari kita bayangkan bahwa perusahaan tersebut berjalan dengan baik. Oleh karena itu, mereka memutuskan untuk memperluas cakupan kegiatannya dan membuka departemen pengembangan Python. Dan di sini timbul pertanyaan: Bagaimana menggambarkan departemen ini di tingkat program? Jawaban: Anda perlu “menyalin dan menempel” di mana pun Anda perlu mendeskripsikan departemen ini (metode lama yang bagus🙃). Pertama, mari kita buat kelas itu sendiri, yang akan mendeskripsikan departemen "Pythonists". (Daftar 4)
package org.example;

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

    public String getJob(){
        return "Middle Python developer";
    }
}
Dan kemudian kami akan mentransfernya ke HiringDepartment. Dan HiringDepartment tidak mengatakan apa pun tentang departemen ini. Oleh karena itu, Anda harus membuat objek baru dari kelas PythonDevelopment dan konstruktor yang menerima pengembang Python. Anda juga harus mengubah metode displayInfo() agar dapat menampilkan informasi dengan benar. (Daftar 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());
        }
    }
}
Seperti yang bisa kita lihat, volume kode menjadi dua kali lipat, atau bahkan lebih. Dengan jumlah kode yang besar, keterbacaannya menurun. Dan parahnya kita membuat semua objek secara manual dan membuat kelas-kelas yang sangat bergantung satu sama lain. Oke, kami setuju dengan ini. Mereka hanya mendeskripsikan satu departemen. Kami tidak akan kehilangan apapun dari ini. Nah, bagaimana jika kita menambah departemen lain? Bagaimana jika ada dua? Tiga? Namun tidak ada yang melarang “penambangan dan penggembalaan.” Musim semi.  Pelajaran 2. IoC/DI dalam praktek - 1 Ya, tidak ada yang melarang “Tambang dan Padang Rumput”, tapi itu tidak profesional. Tyzh adalah seorang programmer. Dan di sini Anda dapat menggunakan DI. Artinya, kita akan bekerja bukan di tingkat kelas, tetapi di tingkat antarmuka. Sekarang status objek kita akan disimpan di antarmuka. Dengan cara ini, ketergantungan antar kelas akan minimal. Untuk melakukan hal ini, pertama-tama kita membuat antarmuka Pengembangan, yang memiliki dua metode untuk mendeskripsikan seorang karyawan. (Daftar 6)
package org.example;

public interface Development {
    String getName();
    String getJob();
}
Biarkan dua kelas JavaDevelopment dan PythonDevelopment mengimplementasikan (mewarisi) dari antarmuka ini dan mengganti metode String getName() dan String getJob(). (Daftar 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";
    }
}
Kemudian di kelas HiringDepartment Anda cukup mendefinisikan objek antarmuka bertipe Development dan Anda juga bisa meneruskan objek tersebut ke konstruktor. (Daftar 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());
    }
}
Seperti yang bisa kita lihat, jumlah kodenya berkurang. Dan yang paling penting, ketergantungan diminimalkan. Bagaimana sebenarnya nilai dan ketergantungan diimplementasikan untuk objek ini? Ada tiga cara untuk melakukan injeksi ketergantungan:
  • Menggunakan konstruktor
  • Menggunakan setter
  • Pengkabelan otomatis (pengikatan otomatis)
Implementasi menggunakan konstruktor Sekarang mari kita bicara tentang implementasi menggunakan konstruktor. Lihatlah Listing 9. Konstruktor kelas HiringDepartment mengharapkan objek bertipe Development sebagai masukan. Kami akan mencoba memasukkan dependensi melalui konstruktor ini. Perlu juga dicatat bahwa injeksi ketergantungan dilakukan menggunakan apa yang disebut wadah pegas. Ada tiga cara untuk mengonfigurasi kontainer Spring:
  • Menggunakan file XML (metode usang)
  • Menggunakan anotasi + file XML (Cara modern)
  • Menggunakan kode Java (cara modern)
Kami sekarang menggunakan konfigurasi menggunakan file XML. Meskipun metode ini dianggap ketinggalan jaman, banyak proyek yang masih ditulis dengan cara ini. Oleh karena itu Anda perlu mengetahuinya. Pertama, Anda harus membuat file xml di folder sumber daya. Anda dapat memberinya nama apa pun, tetapi sebaiknya nama yang bermakna. Saya menyebutnya "applicationContext.xml". Musim semi.  Pelajaran 2. IoC/DI dalam praktek - 2 Dalam file ini kita akan menulis potongan kode berikut (Listing 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>
Sekarang, secara berurutan. Delapan baris kode pertama tidak menarik bagi kami, melainkan default. Anda cukup menyalinnya. Tag <bean> </bean> mendefinisikan kacang Spring. Kacang adalah objek yang dibuat dan dikelola oleh wadah Spring. Dengan kata sederhana, wadah Spring sendiri membuat objek kelas baru untuk kita (misalnya: JavaDevelopment javaDevelopment = new JavaDevelopment();). Di dalam tag ini terdapat atribut id dan class. id menentukan nama kacang. Id ini akan digunakan untuk mengakses objek. Ini setara dengan nama objek di kelas Java. class - mendefinisikan nama kelas dimana kacang (objek) kita terikat. Anda harus menentukan path lengkap ke kelas tersebut. Perhatikan kacang HiringDepartment. Di dalam kacang ini ada tag <constructor-arg ref="javaDeveloper"/> lainnya. Di sinilah injeksi ketergantungan terjadi (dalam kasus kami, injeksi menggunakan konstruktor). <constructor-arg> - memberi tahu Spring bahwa container Spring harus mencari dependensi di konstruktor kelas yang ditentukan dalam atribut bean. Dan objek mana yang perlu dikaitkan ditentukan oleh atribut ref , di dalam tag <constructor-arg>. ref - menunjukkan id kacang yang akan dihubungi. Jika di ref alih-alih javaDeveloper kita menentukan id pythonDeveloper, maka koneksi terjadi dengan kelas PythonDevelopmen. Sekarang kita perlu mendeskripsikan kelas Utama. Ini akan terlihat seperti ini: (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(); //Контекст всегда должен закрываться
    }
}
Apa disini?
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Baris ini menghubungkan kelas Main ke file .xml yang mendeskripsikan kacang kita. Nilai yang diteruskan ke konstruktor harus sesuai dengan nama file .xml. (Dalam kasus kami applicationContext.xml).
HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);
Menunjukkan bahwa kita ingin mendapatkan kacang (objek) dari kelas HiringDepartment. Argumen pertama menunjuk ke id kacang yang kita tulis di file xml. Argumen kedua menunjuk ke kelas yang ingin kita hubungi. Proses ini disebut refleksi .
hiringDepartment.displayInfo();
 context.close(); //Контекст всегда должен закрываться
Di sini kita dengan mudah mendapatkan metode kelas HiringDepartment. Perhatikan bahwa kami tidak menggunakan kata kunci baru untuk mendapatkan objek, dan kami tidak mendefinisikan objek dependen bertipe JavaDevelopment atau PythonDevelopment di mana pun. Mereka dijelaskan secara sederhana dalam file applicationContext.xml. Perhatikan juga baris terakhir. Anda harus selalu menutup konteksnya sebelum mematikannya. Jika tidak, sumber daya tidak akan dibebaskan, dan kebocoran memori atau pengoperasian program yang salah dapat terjadi. Jika Anda memiliki pertanyaan atau saran, tulis di komentar, saya pasti akan menjawab. Terima kasih atas perhatian Anda. Kode sumber di tautan Konten Kursus Kereta GitHub Saya Bersambung...
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION