Suntikan ketergantungan (DI) bukanlah konsep yang mudah untuk difahami, dan menerapkannya pada aplikasi baharu atau sedia ada adalah lebih mengelirukan. Jess Smith menunjukkan kepada anda cara melakukan suntikan kebergantungan tanpa bekas suntikan dalam bahasa pengaturcaraan C# dan Java. Dalam artikel ini, saya akan menunjukkan kepada anda cara melaksanakan suntikan kebergantungan (DI) dalam aplikasi .NET dan Java. Konsep suntikan pergantungan mula mendapat perhatian pembangun pada tahun 2000, apabila Robert Martin menulis artikel "Prinsip dan Corak Reka Bentuk" (kemudian dikenali dengan akronim
SOLID ). D dalam SOLID merujuk kepada Dependency of Inversion (DOI), yang kemudiannya dikenali sebagai suntikan kebergantungan. Definisi asal dan paling biasa: penyongsangan kebergantungan ialah penyongsangan cara kelas asas mengurus kebergantungan. Artikel asal Martin menggunakan kod berikut untuk menggambarkan kebergantungan kelas
Copy
pada kelas peringkat rendah
WritePrinter
:
void Copy()
{
int c;
while ((c = ReadKeyboard()) != EOF)
WritePrinter(c);
}
Masalah pertama yang jelas ialah jika anda menukar senarai parameter atau jenis kaedah
WritePrinter
, anda perlu melaksanakan kemas kini di mana sahaja terdapat pergantungan pada kaedah itu. Proses ini meningkatkan kos penyelenggaraan dan berpotensi menjadi punca ralat baharu.
Masalah lain: kelas Salin bukan lagi calon yang berpotensi untuk digunakan semula. Sebagai contoh, bagaimana jika anda perlu mengeluarkan aksara yang dimasukkan dari papan kekunci ke fail dan bukannya ke pencetak? Untuk melakukan ini, anda boleh mengubah suai kelas
Copy
seperti berikut (sintaks bahasa C++):
void Copy(outputDevice dev)
{
int c;
while ((c = ReadKeyboard()) != EOF)
if (dev == printer)
WritePrinter(c);
else
WriteDisk(c);
}
Walaupun pengenalan kebergantungan baharu
WriteDisk
, keadaan tidak bertambah baik (tetapi bertambah buruk) kerana prinsip lain telah dilanggar: “entiti perisian, iaitu, kelas, modul, fungsi, dan sebagainya, harus dibuka untuk sambungan, tetapi ditutup untuk pengubahsuaian.” Martin menjelaskan bahawa pernyataan bersyarat if/else baharu ini mengurangkan kestabilan dan fleksibiliti kod. Penyelesaiannya adalah untuk menyongsangkan kebergantungan supaya kaedah tulis dan baca bergantung pada
Copy
. Daripada "pop" kebergantungan, ia disalurkan melalui pembina. Kod yang diubah suai kelihatan seperti ini:
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);
}
Kini kelas
Copy
boleh digunakan semula dengan mudah dengan pelaksanaan kaedah kelas
Reader
dan
Writer
. Kelas
Copy
tidak mempunyai apa-apa maklumat tentang struktur dalaman jenis
Reader
dan
Writer
, menjadikannya mungkin untuk digunakan semula dengan pelaksanaan yang berbeza. Tetapi jika semua ini kelihatan seperti semacam gobbledygook kepada anda, mungkin contoh berikut dalam Java dan C# akan menjelaskan keadaan.
Contoh dalam Java dan C#
Untuk menggambarkan kemudahan suntikan kebergantungan tanpa bekas kebergantungan, mari kita mulakan dengan contoh mudah yang boleh disesuaikan untuk digunakan
DI
dalam beberapa langkah sahaja. Katakan kita mempunyai kelas
HtmlUserPresentation
yang, apabila kaedahnya dipanggil, menjana antara muka pengguna HTML. Berikut ialah contoh mudah:
HtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Mana-mana projek yang menggunakan kod kelas ini akan mempunyai pergantungan pada class
HtmlUserPresentation
, mengakibatkan isu kebolehgunaan dan kebolehselenggaraan yang diterangkan di atas. Penambahbaikan serta-merta mencadangkan dirinya sendiri: mencipta antara muka dengan tandatangan semua kaedah yang kini tersedia dalam kelas
HtmlUserPresentation
. Berikut ialah contoh antara muka ini:
public interface IHtmlUserPresentation {
String createTable(ArrayList rowVals, String caption);
String createTableRow(String tableCol);
}
Selepas mencipta antara muka, kami mengubah suai kelas
HtmlUserPresentation
untuk menggunakannya. Kembali ke instantiating type
HtmlUserPresentation
, kita kini boleh menggunakan jenis antara muka dan bukannya jenis asas:
IHtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Mencipta antara muka membolehkan kami menggunakan pelaksanaan lain
IHtmlUserPresentation
. Sebagai contoh, jika kita ingin menguji jenis ini, kita boleh dengan mudah menggantikan jenis asas
HtmlUserPresentation
dengan jenis lain yang dipanggil
HtmlUserPresentationTest
. Perubahan yang dibuat setakat ini menjadikan kod lebih mudah untuk diuji, diselenggara dan skala, tetapi tidak melakukan apa-apa untuk digunakan semula kerana semua
HtmlUserPresentation
kelas yang menggunakan jenis itu masih mengetahui kewujudannya. Untuk mengalih keluar pergantungan langsung ini, anda boleh menghantar jenis antara muka
IHtmlUserPresentation
kepada pembina (atau senarai parameter kaedah) kelas atau kaedah yang akan menggunakannya:
public UploadFile(IHtmlUserPresentation htmlUserPresentation)
Pembina
UploadFile
kini mempunyai akses kepada semua fungsi type
IHtmlUserPresentation
, tetapi tidak mengetahui apa-apa tentang struktur dalaman kelas yang melaksanakan antara muka ini. Dalam konteks ini, suntikan jenis berlaku apabila contoh kelas dibuat
UploadFile
. Jenis antara muka
IHtmlUserPresentation
boleh diguna semula dengan menghantar pelaksanaan berbeza kepada kelas atau kaedah berbeza yang memerlukan fungsi berbeza.
Kesimpulan dan cadangan untuk menyatukan bahan
Anda belajar tentang suntikan pergantungan dan kelas dikatakan bergantung secara langsung antara satu sama lain apabila salah satu daripada mereka membuat instantiat yang lain untuk mendapatkan akses kepada kefungsian jenis sasaran. Untuk memisahkan pergantungan langsung antara kedua-dua jenis, anda harus membuat antara muka. Antara muka memberikan jenis keupayaan untuk memasukkan pelaksanaan yang berbeza, bergantung pada konteks fungsi yang diperlukan. Dengan menghantar jenis antara muka kepada pembina kelas atau kaedah, kelas/kaedah yang memerlukan fungsi tidak mengetahui sebarang butiran tentang jenis yang melaksanakan antara muka. Oleh sebab itu, jenis antara muka boleh digunakan semula merentas kelas berbeza yang memerlukan tingkah laku yang serupa, tetapi tidak serupa.
- Untuk bereksperimen dengan suntikan pergantungan, lihat kod anda daripada satu atau lebih aplikasi dan cuba tukar jenis asas yang banyak digunakan kepada antara muka.
- Tukar kelas yang secara langsung membuat jenis asas ini untuk menggunakan jenis antara muka baharu ini dan hantarkannya melalui senarai pembina atau parameter kaedah kelas yang akan menggunakannya.
- Buat pelaksanaan ujian untuk menguji jenis antara muka ini. Setelah kod anda difaktorkan semula,
DI
ia akan menjadi lebih mudah untuk dilaksanakan dan anda akan melihat betapa lebih fleksibel aplikasi anda dari segi penggunaan semula dan kebolehselenggaraan.
GO TO FULL VERSION