و به این ترتیب... در درس قبل به طور مختصر قسمت نظری IoC و DI را مرور کردیم. ما همچنین فایل پیکربندی pom.xml را برای پروژه خود تنظیم کردیم. امروز شروع به ایجاد قسمت اصلی برنامه می کنیم. ابتدا به شما نشان خواهم داد که چگونه یک برنامه بدون IoC / DI ایجاد کنید. و سپس به طور مستقیم برنامه ای ایجاد خواهیم کرد که به طور مستقل وابستگی ها را معرفی می کند. یعنی کنترل کد به دست فریم ورک می رسد (به نظر وحشتناک می رسد). در حالی که ما برنامه را مدیریت می کنیم، تصور کنید که یک شرکت خاص وجود دارد. و این شرکت (در حال حاضر) دارای دو بخش است: بخش توسعه جاوا و بخش استخدام. اجازه دهید کلاسی که "دپارتمان توسعه جاوا" را توصیف می کند، دو روش داشته باشد: 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
حالا بیایید تصور کنیم که شرکت در حال انجام عالی است. از این رو تصمیم گرفتند که دامنه فعالیت خود را گسترش دهند و یک بخش توسعه پایتون افتتاح کردند. و در اینجا این سوال مطرح می شود: چگونه می توان این بخش را در سطح برنامه توصیف کرد؟ پاسخ: شما باید هر جا که نیاز به توضیح این بخش دارید "کپی و پیست" کنید (روش خوب قدیمی🙃). ابتدا، بیایید خود کلاس را ایجاد کنیم، که بخش "Pythonists" را توصیف می کند. (فهرست 4)
package org.example;
public class PythonDevelopment {
public String getName(){
return "Mike";
}
public String getJob(){
return "Middle Python developer";
}
}
و سپس آن را به بخش استخدام منتقل می کنیم. و بخش استخدام چیزی در مورد این بخش نمی گوید. بنابراین، شما باید یک شی جدید از کلاس PythonDevelopment و سازنده ای ایجاد کنید که توسعه دهندگان پایتون را بپذیرد. همچنین باید متد 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());
}
}
}
همانطور که می بینیم، حجم کد دو برابر یا حتی بیشتر شده است. با حجم زیاد کد، خوانایی آن کاهش می یابد. و بدترین چیز این است که ما همه اشیاء را به صورت دستی ایجاد می کنیم و کلاس هایی می سازیم که به شدت به یکدیگر وابسته هستند. باشه ما با این موافق بودیم آنها فقط یک بخش را توصیف کردند. ما چیزی از این از دست نخواهیم داد خوب، اگر بخش دیگری را اضافه کنیم چه؟ اگه دوتا باشه چی؟ سه؟ اما هیچ کس «معدن و چرا کردن» را ممنوع نکرد. بله، هیچ کس "معدن و مرتع" را ممنوع نکرده است، اما حرفه ای نیست. تایژ یک برنامه نویس است. و در اینجا می توانید از 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());
}
}
همانطور که می بینیم مقدار کد کاهش یافته است. و مهمتر از همه، وابستگی ها به حداقل رسید. ارزش ها و وابستگی ها در واقع برای این اشیا چگونه پیاده سازی می شوند؟ سه راه برای انجام تزریق وابستگی وجود دارد:
- با استفاده از سازنده
- استفاده از ستترها
- سیم کشی خودکار (صحافی خودکار)
- استفاده از فایل های XML (روش قدیمی)
- استفاده از حاشیه نویسی + فایل های XML (روش مدرن)
- استفاده از کد جاوا (روش مدرن)
<?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 را تعریف می کند. لوبیا جسمی است که توسط یک ظرف Spring ایجاد و مدیریت می شود. به عبارت ساده، کانتینر Spring خودش یک شی کلاس جدید برای ما ایجاد می کند (مثلا: JavaDevelopment javaDevelopment = new JavaDevelopment();). در داخل این تگ ویژگی های id و class وجود دارد. id نام لوبیا را مشخص می کند. این شناسه برای دسترسی به شی مورد استفاده قرار خواهد گرفت. معادل نام یک شی در کلاس جاوا است. class - نام کلاسی را که bean (شیء) ما به آن مقید شده است را مشخص می کند. شما باید مسیر کامل کلاس را مشخص کنید. به استخدام دپارتمان توجه کنید. داخل این bean تگ دیگر <constructor-arg ref="javaDeveloper"/> وجود دارد. اینجاست که تزریق وابستگی اتفاق میافتد (در مورد ما، تزریق با استفاده از سازنده). <constructor-arg> - به Spring می گوید که ظرف Spring باید به دنبال وابستگی ها در سازنده کلاس تعریف شده در ویژگی bean باشد. و اینکه کدام شی باید با آن مرتبط شود توسط ویژگی ref در داخل تگ <constructor-arg> تعیین می شود. ref - نشان دهنده شناسه لوبیا برای تماس است. اگر در ref به جای javaDeveloper id 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");
این خط کلاس Main را به فایل xml. پیوند می دهد که bean های ما را توصیف می کند. مقدار ارسال شده به سازنده باید با نام فایل 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 محتوای دوره ادامه دارد...
GO TO FULL VERSION