Saya ingin mengajukan beberapa pertanyaan tentang praktik terbaik mengenai tipe pemetaan dan menggunakan metode ekstensi dalam C #. Saya tahu topik ini telah dibahas beberapa kali selama beberapa tahun terakhir, tetapi saya telah membaca banyak posting dan masih ragu.
Masalah yang saya temui adalah memperluas kelas yang saya miliki dengan fungsionalitas "convert". Katakanlah saya memiliki kelas "Person" yang mewakili objek yang akan digunakan oleh beberapa logika. Saya juga memiliki kelas "Pelanggan" yang mewakili respons dari API eksternal (sebenarnya akan ada lebih dari satu API, jadi saya perlu memetakan setiap respons API ke tipe umum: Orang). Saya memiliki akses ke kode sumber kedua kelas dan secara teoritis dapat menerapkan metode saya sendiri di sana. Saya perlu mengonversi Pelanggan ke Orang agar saya dapat menyimpannya ke basis data. Proyek tidak menggunakan pemetaan otomatis.
Saya memiliki 4 kemungkinan solusi dalam pikiran:
Metode ToTerson () di kelas konsumen. Ini sederhana, tetapi sepertinya mematahkan pola Tanggung Jawab Tunggal kepada saya, terutama bahwa kelas Konsumen dipetakan ke kelas lain (beberapa diperlukan oleh API eksternal lain) juga, jadi itu perlu mengandung beberapa metode pemetaan.
Memetakan konstruktor di kelas Person menggunakan Konsumen sebagai argumen. Juga mudah dan sepertinya juga melanggar pola Tanggung Jawab Tunggal. Saya perlu memiliki beberapa konstruktor pemetaan (karena akan ada kelas dari API lain, memberikan data yang sama dengan Konsumen tetapi dalam format yang sedikit berbeda)
Kelas konverter dengan metode ekstensi. Dengan cara ini saya dapat menulis metode .ToPerson () untuk kelas Konsumen dan ketika API lain diperkenalkan dengan kelas NewConsumer itu sendiri, saya hanya dapat menulis metode ekstensi lain dan menyimpan semuanya dalam file yang sama. Saya pernah mendengar pendapat bahwa metode penyuluhan adalah kejahatan pada umumnya dan harus digunakan hanya jika benar-benar diperlukan sehingga itulah yang menghambat saya. Kalau tidak, saya suka solusi ini
Kelas konverter / mapper. Saya membuat kelas terpisah yang akan menangani konversi dan menerapkan metode yang akan mengambil instance kelas sumber sebagai argumen dan mengembalikan instance kelas tujuan.
Singkatnya, masalah saya dapat dikurangi menjadi sejumlah pertanyaan (semua dalam konteks dengan apa yang saya jelaskan di atas):
Apakah memasukkan metode konversi ke dalam objek (POCO?) (Seperti metode .ToPerson () di kelas Konsumen) dianggap melanggar pola tanggung jawab tunggal?
Apakah menggunakan konstruktor konversi di (seperti DTO) dianggap melanggar pola tanggung jawab tunggal? Terutama jika kelas seperti itu dapat dikonversi dari beberapa jenis sumber, jadi beberapa konstruktor konversi akan diperlukan?
Apakah menggunakan metode ekstensi sambil memiliki akses ke kode sumber kelas asli dianggap praktik buruk? Bisakah perilaku seperti itu digunakan sebagai pola yang layak untuk memisahkan logika atau apakah itu anti-pola?
sumber
Person
kelas itu DTO? apakah itu mengandung perilaku?Jawaban:
Ya, karena pertobatan adalah tanggung jawab lain.
Ya, pertobatan adalah tanggung jawab lain. Tidak ada bedanya jika Anda melakukannya melalui konstruktor atau melalui metode konversi (misalnya
ToPerson
).Belum tentu. Anda dapat membuat metode ekstensi bahkan jika Anda memiliki kode sumber kelas yang ingin Anda perluas. Saya pikir apakah Anda membuat metode ekstensi atau tidak harus ditentukan oleh sifat metode tersebut. Misalnya, apakah ini mengandung banyak logika? Apakah itu tergantung pada sesuatu yang lain dari anggota objek itu sendiri? Saya akan mengatakan bahwa Anda seharusnya tidak memiliki metode ekstensi yang memerlukan dependensi untuk bekerja atau yang mengandung logika kompleks. Hanya logika yang paling sederhana yang harus dimuat dalam metode ekstensi.
Jika logikanya kompleks, maka saya pikir Anda tidak harus menggunakan metode ekstensi. Seperti yang saya sebutkan sebelumnya, Anda harus menggunakan metode ekstensi hanya untuk hal-hal sederhana. Saya tidak akan menganggap konversi sederhana.
Saya sarankan Anda membuat layanan konversi. Anda dapat memiliki antarmuka generik tunggal untuk itu seperti ini:
Dan Anda dapat memiliki konverter seperti ini:
Dan Anda bisa menggunakan Dependency Injection untuk menyuntikkan konverter (misalnya
IConverter<Person,Customer>
) ke kelas apa saja yang membutuhkan kemampuan untuk mengkonversi antaraPerson
danCustomer
.sumber
IConverter
dalam framework, tinggal menunggu untuk diimplementasikan.IConvertable
, bukan itu yang kami cari di sini. Kesalahanku.Converter
digunakanList
saat meneleponConvertAll
. msdn.microsoft.com/en-us/library/kt456a2y(v=vs.110).aspx Saya tidak tahu seberapa berguna itu untuk OP.Iya. Sebuah
Consumer
kelas bertanggung jawab untuk memegang data yang berhubungan dengan konsumen (dan mungkin melakukan beberapa tindakan) dan tidak bertanggung jawab untuk mengkonversi sendiri ke dalam, jenis yang tidak terkait lain.Mungkin. Saya biasanya memiliki metode di luar domain dan objek DTO untuk melakukan konversi. Saya sering menggunakan repositori yang mengambil objek domain dan (de) membuat serial mereka, baik ke database, memori, file, apa pun. Jika saya menempatkan logika itu di kelas domain saya, sekarang saya sudah mengikatnya ke satu bentuk serialisasi tertentu, yang buruk untuk pengujian (dan hal-hal lain). Jika saya menempatkan logika di kelas DTO saya, maka saya telah mengikatnya ke domain saya, lagi-lagi membatasi pengujian.
Tidak secara umum, meskipun mereka bisa digunakan secara berlebihan. Dengan metode ekstensi, Anda membuat ekstensi opsional yang membuat kode lebih mudah dibaca. Mereka memang memiliki kekurangan - lebih mudah untuk menciptakan ambiguitas yang harus diselesaikan oleh kompiler (terkadang secara diam-diam) dan dapat membuat kode lebih sulit untuk di-debug karena tidak sepenuhnya jelas dari mana metode ekstensi berasal.
Dalam kasus Anda, kelas konverter atau mapper sepertinya pendekatan yang paling sederhana, paling mudah, meskipun saya tidak berpikir Anda melakukan kesalahan dengan menggunakan metode ekstensi.
sumber
Bagaimana dengan menggunakan AutoMapper atau custom mapper bisa digunakan Suka
dari domain
Di bawah tenda Anda bisa mengabstraksi AutoMapper atau menggulung mapper Anda sendiri
sumber
Saya tahu ini sudah tua, tetapi masih bersuka ria. Ini akan memungkinkan Anda untuk mengkonversi kedua cara. Saya menemukan ini membantu ketika bekerja dengan Entity Framework dan membuat viewmodels (DTO's).
Saya menemukan AutoMapper sedikit banyak untuk melakukan operasi pemetaan yang sangat sederhana.
sumber