JavaRush /مدونة جافا /Random-AR /ربيع. الدرس 2. IoC/DI في الممارسة العملية
Umaralikhon
مستوى
Красноярск

ربيع. الدرس 2. IoC/DI في الممارسة العملية

نشرت في المجموعة
وهكذا... قمنا في الدرس السابق بمراجعة مختصرة للجزء النظري من IoC وDI. قمنا أيضًا بإعداد ملف التكوين pom.xml لمشروعنا. اليوم نبدأ في إنشاء الجزء الرئيسي من البرنامج. أولاً، سأوضح لك كيفية إنشاء برنامج بدون IoC/DI. وبعد ذلك سنقوم مباشرة بإنشاء برنامج يقدم التبعيات بشكل مستقل. أي أن التحكم في الكود ينتقل إلى أيدي الإطار (يبدو مخيفًا). ونحن ندير البرنامج، تخيل أن هناك شركة معينة. والشركة (في الوقت الحالي) لديها قسمان: قسم تطوير وتوظيف جافا. اسمح للفئة التي تصف "قسم تطوير Java" بطريقتين: String getName() - إرجاع اسم الموظف، String getJob() - إرجاع منصب الموظف. (قائمة 1)
package org.example;

public class JavaDevelopment {

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

    public String getJob(){
        return "Middle Java developer";
    }
}
دع الفصل الذي يصف قسم التوظيف يحتوي على مُنشئ إدخال يقبل الموظف، وطريقة 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());
    }
}
هناك أيضًا فئة رئيسية - وهي فئة تدير جميع الأقسام. (قائمة 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
الآن دعونا نتخيل أن الشركة تعمل بشكل رائع. لذلك، قرروا توسيع نطاق أنشطتهم وافتتحوا قسم تطوير بايثون. وهنا يطرح السؤال: كيف نصف هذا القسم على مستوى البرنامج؟ الإجابة: تحتاج إلى "النسخ واللصق" أينما تريد وصف هذا القسم (الطريقة القديمة الجيدة🙃). أولاً، لنقم بإنشاء الفصل نفسه، والذي يصف قسم "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());
    }
}
كما نرى، انخفض مقدار التعليمات البرمجية. والأهم من ذلك، تم تقليل التبعيات. كيف يتم تنفيذ القيم والتبعيات فعليًا لهذه الكائنات؟ هناك ثلاث طرق للقيام بحقن التبعية:
  • باستخدام المنشئ
  • باستخدام واضعي
  • التوصيل التلقائي (الربط التلقائي)
التنفيذ باستخدام المنشئ الآن دعونا نتحدث عن التنفيذ باستخدام المنشئ. انظر إلى القائمة 9. يتوقع منشئ فئة HiringDepartment كائنًا من النوع Development كمدخل. سنحاول إدخال التبعيات من خلال هذا المنشئ. ومن الجدير بالذكر أيضًا أن حقن التبعية يتم باستخدام ما يسمى بحاويات الربيع. هناك ثلاث طرق لتكوين حاويات الربيع:
  • استخدام ملفات XML (طريقة قديمة)
  • استخدام التعليقات التوضيحية + ملفات XML (الطريقة الحديثة)
  • استخدام كود جافا (الطريقة الحديثة)
نحن نستخدم الآن التكوين باستخدام ملفات 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. بكلمات بسيطة، تقوم حاوية Spring نفسها بإنشاء كائن فئة جديد لنا (على سبيل المثال: JavaDevelopment javaDevelopment = new JavaDevelopment();). يوجد داخل هذه العلامة سمات المعرف والفئة. يحدد المعرف اسم الحبة. سيتم استخدام هذا المعرف للوصول إلى الكائن. إنه يعادل اسم كائن في فئة Java. فئة - تحدد اسم الفئة التي يرتبط بها الفول (الكائن) الخاص بنا. يجب عليك تحديد المسار الكامل للفئة. انتبه إلى حبة قسم التوظيف. يوجد داخل هذه الحبة علامة <constructor-arg ref="javaDeveloper"/> أخرى. هذا هو المكان الذي يحدث فيه حقن التبعية (في حالتنا، الحقن باستخدام المُنشئ). <constructor-arg> - يخبر Spring أن حاوية Spring يجب أن تبحث عن التبعيات في مُنشئ الفئة المحدد في سمة الحبة. ويتم تحديد الكائن الذي يجب الارتباط به من خلال سمة ref ، داخل علامة <constructor-arg>. المرجع - يشير إلى معرف الحبة المراد الاتصال بها. إذا قمنا بتحديد معرف pythonDeveloper في المرجع بدلاً من javaDeveloper، فسيتم الاتصال بفئة PythonDevelopmen. الآن نحن بحاجة إلى وصف الطبقة الرئيسية. سيبدو هكذا: (القائمة 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(); //Контекст всегда должен закрываться
    }
}
ماذا هنا؟
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
يربط هذا السطر الفئة الرئيسية بملف .xml الذي يصف حبوبنا. يجب أن تتطابق القيمة التي تم تمريرها إلى المنشئ مع اسم ملف .xml. (في حالتنا applicationContext.xml).
HiringDepartment hiringDepartment = context.getBean("hiringDepartment", HiringDepartment.class);
يشير إلى أننا نريد الحصول على حبة (كائن) من فئة HiringDepartment. تشير الوسيطة الأولى إلى معرف الفول الذي كتبناه في ملف XML. تشير الوسيطة الثانية إلى الفصل الذي نريد الاتصال به. هذه العملية تسمى الانعكاس .
hiringDepartment.displayInfo();
 context.close(); //Контекст всегда должен закрываться
هنا نحصل بسهولة على طريقة لفئة HiringDepartment. لاحظ أننا لم نستخدم الكلمة الأساسية الجديدة للحصول على الكائنات، ولم نحدد كائنات تابعة من النوع JavaDevelopment أو PythonDevelopment في أي مكان. لقد تم وصفها ببساطة في ملف applicationContext.xml. انتبه أيضًا إلى السطر الأخير. يجب عليك دائمًا إغلاق السياق قبل إيقاف التشغيل. وإلا، فلن يتم تحرير الموارد، وقد يحدث تسرب للذاكرة أو تشغيل غير صحيح للبرنامج. إذا كان لديك أسئلة أو اقتراحات، فاكتب في التعليقات، وسأجيب بالتأكيد. أشكر لك إهتمامك. كود المصدر على الرابط محتوى الدورة التدريبية لعربة GitHub يتبع ...
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION