Saya hanya belajar tentang injeksi ketergantungan, dan saya terjebak pada sesuatu. Dependency Injection merekomendasikan pengiriman kelas dependen melalui konstruktor, tapi saya ingin tahu apakah ini diperlukan untuk objek data. Karena Unit-Testability adalah salah satu manfaat utama DI, akankah suatu objek data, yang hanya menyimpan data, dan tidak ada prosedur yang pernah diuji unit, membuat DI menjadi lapisan kompleksitas yang tidak perlu, atau apakah itu masih membantu dalam menunjukkan dependensi bahkan dengan objek data?
Class DO{
DO(){
DataObject2List = new List<DO2>();
}
public string Field1;
public string Field2;
public List<DO2> DataObject2List;
}
Class DO2{
public DateTime Date;
public double Value;
}
c#
dependency-injection
class-design
sooprise
sumber
sumber
Jawaban:
Saya ingin menyarankan klarifikasi beberapa terminologi yang Anda gunakan di sini, khususnya "ketergantungan" dan "injeksi ketergantungan".
Ketergantungan:
"Ketergantungan" biasanya adalah objek kompleks yang melakukan beberapa fungsionalitas yang mungkin perlu bergantung pada kelas lain. Beberapa contoh klasik akan menjadi logger atau pengakses database atau beberapa komponen yang memproses bagian tertentu dari logika bisnis.
Sebuah data hanya objek seperti DTO atau objek nilai tidak biasanya disebut sebagai "ketergantungan", karena mereka tidak melakukan beberapa fungsi yang dibutuhkan.
Setelah Anda melihat cara ini, apa yang Anda lakukan dalam contoh Anda ( menyusun satu
DO
objek dengan daftarD02
objek melalui constructor) tidak harus dianggap "dependecy injection" sama sekali. Ini hanya pengaturan properti. Terserah Anda apakah Anda menyediakannya di konstruktor atau cara lain, tetapi hanya meneruskannya melalui konstruktor tidak menjadikannya ketergantungan injeksi.Injeksi Ketergantungan:
Jika
DO2
kelas Anda benar-benar menyediakan beberapa fungsionalitas tambahan yangDO
dibutuhkan kelas, maka itu akan benar-benar menjadi ketergantungan. Dalam hal itu, kelas dependenDO
,, harus bergantung pada antarmuka (seperti ILogger atau IDataAccessor), dan pada gilirannya bergantung pada kode panggilan untuk menyediakan antarmuka itu (dengan kata lain, untuk 'menyuntikkan' keDO
instance).Menyuntikkan ketergantungan sedemikian rupa membuat
DO
objek lebih fleksibel, karena setiap konteks yang berbeda dapat memberikan implementasi antarmuka untukDO
objek itu sendiri. (Pikirkan pengujian unit.)sumber
Saya akan melakukan yang terbaik untuk menghilangkan kebingungan dalam pertanyaan.
Pertama-tama, "Objek Data" bukan istilah yang bermakna. Jika satu - satunya karakteristik yang menentukan dari objek ini adalah bahwa ia tidak memiliki metode, maka seharusnya tidak ada sama sekali . Objek tanpa perilaku yang berguna harus masuk ke dalam setidaknya satu dari subkategori berikut:
Objek Nilai atau "catatan" tidak memiliki identitas sama sekali. Mereka harus tipe nilai , dengan semantik salinan-pada-referensi, dengan asumsi lingkungan mendukungnya. Karena ini adalah struktur tetap, VO hanya boleh menjadi tipe primitif atau urutan primitif tetap. Oleh karena itu, VO tidak boleh memiliki dependensi atau asosiasi apa pun ; konstruktor non-default akan ada hanya untuk tujuan menginisialisasi nilai, yaitu karena tidak dapat dinyatakan sebagai literal.
Objek Transfer Data sering keliru dikacaukan dengan objek nilai. DTO memang memiliki identitas, atau setidaknya mereka bisa . Satu-satunya tujuan DTO adalah untuk memfasilitasi aliran informasi dari satu domain ke domain lainnya. Mereka tidak pernah memiliki "ketergantungan". Mereka mungkin memiliki asosiasi (yaitu ke array atau koleksi) tetapi kebanyakan orang lebih suka membuatnya datar. Pada dasarnya, mereka analog dengan baris dalam output dari query database; mereka adalah objek sementara yang biasanya perlu dipertahankan atau diserialisasi, dan karenanya tidak dapat merujuk jenis abstrak apa pun, karena ini akan membuatnya tidak dapat digunakan.
Akhirnya, Data Access Objects menyediakan pembungkus atau façade ke suatu jenis database. Ini jelas memiliki dependensi - mereka tergantung pada koneksi database dan / atau komponen ketekunan. Namun, ketergantungan mereka hampir selalu dikelola secara eksternal dan sama sekali tidak terlihat oleh penelepon. Dalam pola Rekaman Aktif itu adalah kerangka kerja yang mengelola semuanya melalui konfigurasi; dalam model DAO yang lebih tua (kuno menurut standar saat ini) Anda hanya bisa membuatnya melalui wadah. Jika saya melihat salah satunya dengan injeksi konstruktor, saya akan sangat, sangat khawatir.
Anda juga mungkin berpikir dari objek entitas atau "objek bisnis" , dan dalam hal ini Anda lakukan ingin dukungan injeksi ketergantungan, tapi tidak dalam cara yang menurut Anda atau untuk alasan yang Anda pikirkan. Ini bukan untuk kepentingan kode pengguna , itu untuk kepentingan manajer entitas atau ORM, yang akan secara diam-diam menyuntikkan proksi yang disadap untuk melakukan hal-hal mewah seperti pemahaman kueri atau pemuatan malas.
Dalam hal ini, Anda biasanya tidak menyediakan konstruktor untuk injeksi; alih-alih, Anda hanya perlu membuat properti virtual dan menggunakan tipe abstrak (mis.
IList<T>
alih-alihList<T>
). Sisanya terjadi di belakang layar, dan tidak ada yang lebih bijak.Jadi, secara keseluruhan, saya akan mengatakan bahwa pola DI yang terlihat sedang diterapkan ke "objek data" tidak diperlukan dan bahkan mungkin bendera merah; tetapi sebagian besar, itu karena keberadaan objek adalah bendera merah, kecuali dalam kasus ketika objek tersebut secara khusus digunakan untuk mewakili data dari database. Dalam hampir setiap kasus lain itu adalah bau kode, biasanya awal dari Model Domain Anemik atau setidaknya Poltergeist .
Untuk mengulangi:
Sirip.
sumber
Dalam contoh Anda,
DO
tidak memiliki dependensi fungsional (pada dasarnya karena tidak melakukan apa-apa). Itu memang memiliki ketergantungan pada jenis betonDO2
, jadi Anda mungkin ingin memperkenalkan antarmuka ke abstrakDO2
, sehingga konsumen dapat mengimplementasikan implementasi konkret mereka sendiri dari kelas anak.Sungguh, ketergantungan apa yang akan Anda suntikkan di sini?
sumber
DOPersister
yang tahu cara bertahanDO
dan meninggalkannya sebagai objek hanya data semata (lebih baik menurut saya). Dalam kasus terakhir,DOPersister
akan disuntikkan dengan ketergantungan database.Karena ini adalah Objek Data di lapisan akses data, itu harus bergantung langsung pada layanan database. Anda bisa menentukan Layanan Database untuk konstruktor:
Tapi, injeksi tidak harus di dalam konstruktor. Atau, Anda bisa memberikan ketergantungan melalui setiap metode CRUD. Saya lebih suka metode ini daripada yang sebelumnya karena Objek Data Anda tidak perlu tahu di mana itu akan bertahan sampai Anda benar-benar perlu bertahan.
Anda tentu tidak ingin menyembunyikan konstruksi dengan metode CRUD!
Opsi alternatif adalah membangun DatabaseService melalui metode kelas yang dapat ditimpa.
Alternatif terakhir adalah menggunakan ServiceLocator gaya tunggal. Meskipun saya tidak suka opsi ini, itu bisa diuji unit.
sumber