Cara menggunakan Injeksi Ketergantungan bersamaan dengan pola Pabrik

10

Pertimbangkan modul yang bertanggung jawab untuk mem-parsing file dari jenis apa pun yang diberikan. Saya sedang berpikir untuk menggunakan pola strategi untuk mengatasi masalah ini seperti yang telah saya jelaskan di sini . Silakan merujuk ke posting terkait sebelum melanjutkan dengan pertanyaan ini.

Pertimbangkan kelas B yang membutuhkan konten file product.xml. Kelas ini perlu instantiate implementator beton yang sesuai dari antarmuka Parser untuk mem-parsing file XML. Saya dapat mendelegasikan Instansiasi pelaksana beton yang tepat untuk Pabrik sehingga kelas B "memiliki-a" Pabrik. Namun, kelas B kemudian akan "bergantung" pada Pabrik untuk instantiating pelaksana beton. Ini berarti bahwa konstruktor atau metode penyetel di kelas B perlu melewati Pabrik.

Oleh karena itu, Pabrik dan kelas B yang perlu mengurai file akan digabungkan satu sama lain. Saya mengerti bahwa saya mungkin benar-benar salah tentang apa pun yang telah saya jelaskan sejauh ini. Saya ingin tahu apakah saya dapat menggunakan injeksi ketergantungan dalam skenario di mana ketergantungan yang akan disuntikkan adalah Pabrik dan apa yang akan menjadi cara yang tepat untuk menerapkan ini sehingga saya dapat mengambil keuntungan dari bidang-bidang seperti mengejek Pabrik di unit test saya.

CKing
sumber

Jawaban:

8

Cara yang tepat untuk melakukan ini adalah dengan bergantung pada antarmuka, dan kemudian menyuntikkan implementasi antarmuka itu ke dalam Kelas B.

Antarmuka hanyalah hal tertipis yang dapat Anda andalkan - saya mempersamakannya dengan mencoba mengambil setitik asap. Kode harus dipasangkan dengan sesuatu atau tidak akan melakukan apa pun, tetapi menyambungkan ke antarmuka hampir terpisah seperti yang Anda dapatkan, namun antarmuka dapat menyediakan semua fungsi yang Anda inginkan.

Jadi mintalah konstruktor Kelas B mengambil antarmuka ke kelas yang dibutuhkannya, dan minta pabrik membuat kelas itu sebagai pelaksana antarmuka. Jangan bergantung pada pabrik, bergantung pada antarmuka, dan minta pabrik menyediakan implementasi dari pabrik itu.

Jadi ya, Anda akan menggunakan injeksi ketergantungan, tetapi tidak ada yang salah dengan itu. Injeksi ketergantungan - khususnya injeksi konstruktor sederhana - harus menjadi cara "normal" dalam melakukan sesuatu. Sederhananya menunda hal-hal baru di aplikasi Anda (dan sedekat mungkin dengan baris pertama main), dan sembunyikan panggilan baru di kelas yang dirancang khusus untuk menciptakan sesuatu.

Intinya: Jangan ragu untuk menyuntikkan dependensi. Itu harus menjadi cara normal dalam melakukan sesuatu.

Nick Hodges
sumber
Apakah injeksi konstruktor menunda hal-hal baru selama mungkin?
JeffO
Itu salah tempat - saya sudah memperbaikinya untuk mengatakan "sejauh mungkin di aplikasi Anda".
Nick Hodges
Iya. Saya berpikir untuk bergantung pada antarmuka Parser, bukan pabrik. Sekarang jika kelas lain menggunakan kelas B, itu harus bergantung pada antarmuka yang bergantung pada kelas B. Ini akan terus berlanjut hingga kelas tingkat atas. Kelas tingkat atas ini akhirnya harus menggunakan pabrik untuk membuat instance konkret yang sesuai dari Parser. Haruskah kelas tingkat atas bergantung pada pabrik atau haruskah menggunakan pabrik langsung di dalam metodenya?
CKing
1
Kata baik: Jangan ragu untuk menyuntikkan dependensi
Signcodeindie
9

Saya pikir premis Anda agak bingung di sini, Anda berbicara tentang menyuntikkan pabrik, tetapi pola pabrik adalah pola kreatif yang tujuannya adalah untuk melakukan subset dari apa yang dilakukan kerangka kerja injeksi ketergantungan, ketika kerangka kerja DI tidak lazim pola ini adalah berguna karena alasan itu. Namun jika Anda memiliki kerangka kerja DI, Anda tidak lagi benar-benar membutuhkan pabrik karena kerangka kerja DI dapat memenuhi tujuan yang seharusnya dipenuhi oleh pabrik.

Yang mengatakan, izinkan saya menjelaskan sedikit tentang injeksi ketergantungan dan bagaimana Anda biasanya akan menggunakannya.

Ada berbagai cara untuk melakukan injeksi ketergantungan, tetapi yang paling umum adalah injeksi konstruktor, injeksi properti, dan DIContainer langsung. Saya akan berbicara mengenai injeksi konstruktor karena injeksi properti adalah pendekatan yang salah sebagian besar waktu (pendekatan yang tepat beberapa waktu), dan akses DIContainer tidak disukai kecuali ketika Anda benar-benar tidak dapat melakukan salah satu dari pendekatan lain.

Injeksi konstruktor adalah tempat Anda memiliki antarmuka untuk dependensi dan DIContainer (atau pabrik) yang mengetahui implementasi konkret untuk dependensi itu, dan di mana pun Anda membutuhkan objek yang bergantung pada antarmuka itu, pada saat konstruksi Anda menyerahkan implementasi dari pabrik ke Itu.

yaitu

IDbConnectionProvider connProvider = DIContainer.Get<IDbConnectionProvider>();
IUserRepository userRepo = new UserRepository(connProvider);
User currentUser = userRepo.GetCurrentUser();

Banyak kerangka kerja DI dapat menyederhanakan ini secara signifikan ke tempat DIContainer Anda akan memeriksa konstruktor UserRepository untuk antarmuka yang dikenal dengan implementasi konkret, dan secara otomatis akan menyerahkannya kepada Anda; teknik ini sering disebut Inversion of Control, meskipun DI dan IoC keduanya istilah yang dipertukarkan banyak dan memiliki perbedaan yang samar (jika ada).

Sekarang jika Anda bertanya-tanya bagaimana kode menyeluruh mengakses DIContainer, baik Anda dapat memiliki kelas statis untuk mengaksesnya atau apa yang lebih tepat adalah bahwa sebagian besar kerangka kerja DI memungkinkan Anda untuk membuat DIContainer baru, di mana ia sebenarnya hanya akan berperilaku sebagai bungkus ke kamus tunggal internal untuk jenis yang diketahuinya konkret untuk antarmuka yang diberikan.

Itu artinya, Anda dapat membuat DIContainer baru di mana saja yang Anda inginkan dalam kode dan secara efektif mendapatkan DIContainer yang telah Anda konfigurasikan untuk mengetahui hubungan antar muka dengan beton. Cara biasa menyembunyikan DIContainer dari bagian kode yang tidak boleh berinteraksi dengannya secara langsung adalah hanya memastikan hanya proyek yang diperlukan yang memiliki referensi ke kerangka kerja DI.

Jimmy Hoffa
sumber
Saya tidak sepenuhnya setuju dengan paragraf pertama. Masih ada skenario di mana Anda bergantung pada pabrik (mengimplementasikan inteface) yang disuntikkan oleh wadah DI.
Piotr Perak
Saya pikir Anda melewatkan intinya karena OP tidak berbicara tentang kerangka kerja DI atau wadah DI.
Doc Brown
@ Jimmy Hoffa Sementara Anda membuat beberapa poin yang sangat menarik, saya menyadari wadah IoC seperti Spring dan konsep Dependency Injection. Kekhawatiran saya adalah tentang skenario di mana Anda tidak menggunakan kerangka kerja IoC dalam hal ini, Anda perlu menulis kelas yang akan membuat instantiate dependensi Anda untuk Anda. Jika kelas A bergantung pada antarmuka B dan kelas C menggunakan kelas A, maka kelas C tergantung pada antarmuka B. Seseorang harus memberi Kelas C Kelas B. Haruskah kelas C tergantung pada cla
CKing
Jika kelas A tergantung pada antarmuka B dan kelas C menggunakan kelas A, maka kelas C tergantung pada antarmuka B. Seseorang harus memberi Kelas C antarmuka B. Haruskah kelas C bergantung pada antarmuka B atau haruskah tergantung pada kelas yang dipakai oleh dependensi Yaitu pabrik. Anda sepertinya telah menjawab pertanyaan ini dalam jawaban Anda tetapi dengan informasi yang berlebihan :)
CKing
@bot seperti yang saya katakan di kata pengantar, sebagian besar Anda dapat memperlakukan pabrik sebagai bagian dari fungsi wadah DI, itu tidak benar dalam semua skenario seperti yang disebutkan Doc Brown, tetapi lihat contoh kode saya dan ganti DIContainerdengan DbConnectionFactorydan konsep masih berdiri bahwa Anda akan mengambil implementasi konkret dari DI / Pabrik / etc Anda dan menyerahkannya kepada konsumen jenis pada waktu konstruksi mereka.
Jimmy Hoffa
5

Anda dapat melewati pabrik melalui injeksi ketergantungan sama seperti Anda melewati apa pun, jangan biarkan situasi yang berulang membuat Anda bingung. Saya tidak tahu harus berkata apa lagi tentang mengimplementasikannya - Anda sudah tahu cara melakukan injeksi ketergantungan.

Saya menggunakan DI untuk menyuntikkan pabrik secara teratur.

psr
sumber
1
Jika kelas tergantung pada Pabrik, Anda harus mengejek pabrik saat unit menguji kelas itu. Bagaimana Anda melakukannya? Biarkan kelas bergantung pada antarmuka pabrik?
CKing
4

Tidak ada yang salah dalam menyuntikkan pabrik. Ini adalah cara standar jika Anda tidak dapat memutuskan selama membangun objek 'induk' jenis ketergantungan apa yang akan Anda butuhkan. Saya pikir contoh akan menjelaskan yang terbaik. Saya akan menggunakan c # karena saya tidak tahu java.


class Parent
{
    private IParserFactory parserFactory;
    public Parent(IParserFactory factory)
    {
        parserFactory = factory
    }

    public ParsedObject ParseFrom(string filename, FileType fileType)
    {
        var parser = parserFactory.CreateFor(fileType);
        return parser.Parse(filename);
    }
}
Piotr Perak
sumber