Dependency injection (DI) başa düşmək asan bir anlayış deyil və onu yeni və ya mövcud tətbiqlərə tətbiq etmək daha da qarışıqdır. Jess Smith sizə C# və Java proqramlaşdırma dillərində inyeksiya konteyneri olmadan asılılıq inyeksiyasını necə edəcəyinizi göstərir. Bu yazıda mən sizə .NET və Java proqramlarında asılılıq inyeksiyasını (DI) necə tətbiq edəcəyinizi göstərəcəyəm. Asılılıq inyeksiya anlayışı ilk dəfə 2000-ci ildə, Robert Martin "Dizayn Prinsipləri və Nümunələri" (sonralar
SOLID abbreviaturası ilə tanınır ) məqaləsini yazan zaman tərtibatçıların diqqətini çəkdi. SOLID-dəki D, sonradan asılılıq inyeksiyası kimi tanınan İnversiyadan Asılılığa (DOI) aiddir. Orijinal və ən ümumi tərif: asılılığın inversiyası əsas sinifin asılılıqları idarə etmə tərzinin inversiyasıdır.
Copy
Martinin orijinal məqaləsində bir sinfin aşağı səviyyəli sinifdən asılılığını göstərmək üçün aşağıdakı koddan istifadə edilmişdir
WritePrinter
:
void Copy()
{
int c;
while ((c = ReadKeyboard()) != EOF)
WritePrinter(c);
}
İlk aşkar problem ondan ibarətdir ki, əgər siz metodun parametr siyahısını və ya növlərini dəyişdirsəniz
WritePrinter
, həmin metoddan asılılıq olan yerdə yeniləmələri həyata keçirməlisiniz. Bu proses texniki xidmət xərclərini artırır və yeni xətaların potensial mənbəyidir.
Başqa bir problem: Copy sinfi artıq təkrar istifadə üçün potensial namizəd deyil. Məsələn, klaviaturadan daxil edilmiş simvolları printerə deyil, fayla çıxarmaq lazımdırsa nə etməli? Bunu etmək üçün sinfi
Copy
aşağıdakı kimi dəyişdirə bilərsiniz (C++ dili sintaksisi):
void Copy(outputDevice dev)
{
int c;
while ((c = ReadKeyboard()) != EOF)
if (dev == printer)
WritePrinter(c);
else
WriteDisk(c);
}
Yeni asılılığın tətbiqinə baxmayaraq
WriteDisk
, vəziyyət yaxşılaşmadı (daha çox pisləşdi), çünki başqa bir prinsip pozuldu: “proqram təminatı obyektləri, yəni siniflər, modullar, funksiyalar və s. genişləndirmək üçün açıq olmalıdır, lakin Modifikasiya." Martin izah edir ki, bu yeni şərti if/else ifadələri kodun sabitliyini və çevikliyini azaldır. Həll yolu asılılıqları çevirməkdir ki, yazma və oxu üsulları
Copy
. Asılılıqları "pop" etmək əvəzinə, onlar konstruktordan keçirilir. Dəyişdirilmiş kod belə görünür:
class Reader
{
public:
virtual int Read() = 0;
};
class Writer
{
public:
virtual void Write(char) = 0;
};
void Copy(Reader& r, Writer& w)
{
int c;
while((c=r.Read()) != EOF)
w.Write(c);
}
İndi sinfi
Copy
sinif metodlarının müxtəlif tətbiqləri ilə asanlıqla təkrar istifadə etmək
Reader
olar
Writer
. Sinifdə
Copy
növlərin daxili quruluşu
Reader
və
Writer
müxtəlif tətbiqlərlə təkrar istifadə edilməsi haqqında heç bir məlumat yoxdur. Ancaq bütün bunlar sizə bir növ laqeydlik kimi görünürsə, ola bilsin ki, Java və C# dillərində aşağıdakı nümunələr vəziyyəti aydınlaşdıracaq.
Java və C#-da nümunə
DI
Asılılıq konteyneri olmadan asılılıq inyeksiyasının asanlığını göstərmək üçün bir neçə addımda istifadə üçün fərdiləşdirilə bilən sadə bir nümunə ilə başlayaq . Tutaq ki
HtmlUserPresentation
, bizdə onun metodları çağırılanda HTML istifadəçi interfeysi yaradan bir sinif var. Budur sadə bir nümunə:
HtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Bu sinif kodundan istifadə edən hər hansı bir layihənin sinifdən asılılığı olacaq
HtmlUserPresentation
və nəticədə yuxarıda təsvir edilən istifadə və davamlılıq problemləri yaranacaq. Təkmilləşdirmə dərhal özünü təklif edir: sinifdə mövcud olan bütün metodların imzaları ilə bir interfeys yaratmaq
HtmlUserPresentation
. Bu interfeysin bir nümunəsidir:
public interface IHtmlUserPresentation {
String createTable(ArrayList rowVals, String caption);
String createTableRow(String tableCol);
}
İnterfeys yaratdıqdan sonra
HtmlUserPresentation
onu istifadə etmək üçün sinfi dəyişdiririk. Növün yaradılmasına qayıdaraq
HtmlUserPresentation
, indi əsas növün əvəzinə interfeys növündən istifadə edə bilərik:
IHtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
İnterfeys yaratmaq bizə proqramın digər tətbiqlərindən asanlıqla istifadə etməyə imkan verir
IHtmlUserPresentation
. Məsələn, bu növü sınaqdan keçirmək istəsək, biz asanlıqla əsas tipini
HtmlUserPresentation
adlı başqa bir tiplə əvəz edə bilərik
HtmlUserPresentationTest
. İndiyə qədər edilən dəyişikliklər kodu sınamağı, saxlamağı və miqyasını asanlaşdırır, lakin təkrar istifadə üçün heç nə etmir, çünki
HtmlUserPresentation
növü istifadə edən bütün siniflər hələ də onun mövcudluğundan xəbərdardır.
IHtmlUserPresentation
Bu birbaşa asılılığı aradan qaldırmaq üçün siz ondan istifadə edəcək sinif və ya metodun konstruktoruna (və ya metod parametrlərinin siyahısına) interfeys növünü ötürə bilərsiniz :
public UploadFile(IHtmlUserPresentation htmlUserPresentation)
İndi konstruktor
UploadFile
növün bütün funksionallığına giriş əldə edir
IHtmlUserPresentation
, lakin bu interfeysi həyata keçirən sinfin daxili strukturu haqqında heç nə bilmir. Bu kontekstdə tip inyeksiyası sinif nümunəsi yaradıldıqda baş verir
UploadFile
. İnterfeys növü
IHtmlUserPresentation
müxtəlif tətbiqləri müxtəlif siniflərə və ya fərqli funksionallıq tələb edən metodlara ötürməklə təkrar istifadə edilə bilən olur.
Nəticə və materialın birləşdirilməsi üçün tövsiyələr
Siz asılılıq inyeksiyası haqqında öyrəndiniz və onlardan biri hədəf növün funksionallığına giriş əldə etmək üçün digərini işə saldıqda siniflərin bir-birindən birbaşa asılı olduğu deyilir. İki növ arasında birbaşa asılılığı ayırmaq üçün interfeys yaratmalısınız. İnterfeys bir növə tələb olunan funksionallığın kontekstindən asılı olaraq müxtəlif tətbiqləri daxil etmək imkanı verir. İnterfeys növünü sinif konstruktoruna və ya metoduna ötürməklə, funksionallığa ehtiyacı olan sinif/metod interfeysi həyata keçirən tip haqqında heç bir təfərrüatı bilmir. Buna görə interfeys növü oxşar, lakin eyni olmayan davranış tələb edən müxtəlif siniflər arasında təkrar istifadə edilə bilər.
- Asılılıq inyeksiyasını sınaqdan keçirmək üçün bir və ya bir neçə proqramdan kodunuza baxın və çox istifadə olunan əsas növünü interfeysə çevirməyə cəhd edin.
- Bu yeni interfeys növündən istifadə etmək üçün bu əsas tipi birbaşa yaradan sinifləri dəyişdirin və onu istifadə edəcək sinif metodunun konstruktoru və ya parametr siyahısından keçirin.
- Bu interfeys növünü yoxlamaq üçün test tətbiqi yaradın. Kodunuz refaktorlaşdırıldıqdan sonra
DI
onu həyata keçirmək daha asan olacaq və siz təkrar istifadə və davamlılıq baxımından tətbiqinizin nə qədər çevik olduğunu görəcəksiniz.
GO TO FULL VERSION