Saya sedang membangun aplikasi WPF menggunakan pola MVVM. Saat ini, model tampilan saya memanggil lapisan layanan untuk mengambil model (bagaimana tidak relevan dengan model tampilan) dan mengubahnya menjadi model tampilan. Saya menggunakan injeksi konstruktor untuk melewati layanan yang diperlukan untuk viewmodel.
Ini mudah diuji dan berfungsi dengan baik untuk model tampilan dengan sedikit dependensi, tetapi segera setelah saya mencoba membuat model viewModels untuk model yang kompleks, saya memiliki konstruktor dengan BANYAK layanan yang disuntikkan di dalamnya (satu untuk mengambil setiap dependensi dan daftar semua nilai yang tersedia) untuk mengikat ke itemSumber misalnya). Saya ingin tahu bagaimana menangani beberapa layanan seperti itu dan masih memiliki model tampilan yang dapat saya uji dengan mudah.
Saya sedang memikirkan beberapa solusi:
Membuat layanan singleton (IServices) yang berisi semua layanan yang tersedia sebagai antarmuka. Contoh: Services.Current.XXXService.Retrieve (), Services.Current.YYYService.Retrieve (). Dengan begitu, saya tidak memiliki konstruktor besar dengan banyak parameter layanan di dalamnya.
Membuat fasad untuk layanan yang digunakan oleh viewModel dan meneruskan objek ini di ctor viewmodel saya. Tapi kemudian, saya harus membuat fasad untuk masing-masing model viewe kompleks saya, dan mungkin agak banyak ...
Menurut Anda apa cara "benar" untuk mengimplementasikan arsitektur semacam ini?
sumber
new
untuk membuat model tampilan lain, tetapi pikirkan sesuatu yang sederhana seperti aplikasi MDI di mana mengklik tombol atau menu "dokumen baru" akan menambah tab baru atau membuka jendela baru. Shell / konduktor harus dapat membuat contoh baru dari sesuatu , bahkan jika itu tersembunyi di balik satu atau beberapa lapisan tipuan.Jawaban:
Faktanya, kedua solusi ini buruk.
Ini pada dasarnya adalah Pola Penentu Lokasi Layanan , yang merupakan anti-pola. Jika Anda melakukan ini, Anda tidak akan lagi dapat memahami apa yang sebenarnya tergantung pada model tampilan tanpa melihat implementasi privatnya, yang akan membuatnya sangat sulit untuk diuji atau diperbaiki.
Ini bukan anti-pola tetapi ini adalah bau kode. Pada dasarnya Anda membuat objek parameter , tetapi titik dari pola PO refactoring adalah untuk berurusan dengan set parameter yang sering digunakan dan di banyak tempat yang berbeda , sedangkan parameter ini hanya akan pernah digunakan sekali. Seperti yang Anda sebutkan, itu akan membuat banyak kode mengasapi tanpa manfaat nyata, dan tidak akan bermain bagus dengan banyak wadah IOC.
Faktanya, kedua strategi di atas mengabaikan masalah keseluruhan, yaitu bahwa pemasangan terlalu tinggi antara model tampilan dan layanan . Cukup menyembunyikan dependensi ini di pelacak layanan atau objek parameter tidak benar-benar mengubah berapa banyak objek lain yang bergantung pada model tampilan.
Pikirkan bagaimana Anda akan menguji unit dari salah satu model tampilan ini. Seberapa besar kode pengaturan Anda? Berapa banyak hal yang perlu diinisialisasi agar dapat berfungsi?
Banyak orang yang memulai dengan MVVM mencoba membuat model tampilan untuk seluruh layar , yang pada dasarnya merupakan pendekatan yang salah. MVVM adalah semua tentang komposisi , dan layar dengan banyak fungsi harus terdiri dari beberapa model tampilan yang berbeda, masing-masing tergantung pada hanya satu atau beberapa model / layanan internal. Jika mereka perlu berkomunikasi satu sama lain, Anda melakukannya melalui pub / sub (perantara pesan, bus acara, dll.)
Apa yang sebenarnya perlu Anda lakukan adalah memperbaiki model tampilan Anda sehingga mereka memiliki lebih sedikit dependensi . Kemudian, jika Anda perlu memiliki "layar" agregat, Anda membuat model tampilan lain untuk mengagregasi model tampilan yang lebih kecil. Model tampilan agregat ini tidak harus melakukan banyak hal dengan sendirinya, sehingga pada gilirannya juga cukup mudah untuk dipahami dan diuji.
Jika Anda telah melakukan ini dengan benar, itu harus jelas hanya dari melihat kode, karena Anda akan memiliki model tampilan pendek, ringkas, spesifik, dan dapat diuji.
sumber
Saya bisa menulis buku tentang ini ... sebenarnya saya;)
Pertama, tidak ada cara "benar" yang universal untuk melakukan sesuatu. Anda harus mempertimbangkan faktor-faktor lain.
Mungkin saja layanan Anda berbutir terlalu halus. Membungkus Layanan dengan Fasad yang menyediakan antarmuka yang menggunakan Viewmodel tertentu atau bahkan sekelompok ViewModels terkait mungkin merupakan solusi yang lebih baik.
Simpler masih akan membungkus layanan menjadi satu fasad yang digunakan semua model viewm. Tentu saja itu berpotensi menjadi antarmuka yang sangat besar dengan banyak fungsi yang tidak perlu untuk skenario rata-rata. Tapi saya akan mengatakan itu tidak berbeda dengan router pesan yang menangani setiap pesan di sistem Anda.
Bahkan, apa yang saya lihat banyak arsitektur akhirnya berkembang menjadi pesan bus dibangun di sekitar sesuatu seperti pola Agregator Acara. Tes mudah dilakukan di sana karena kelas pengujian Anda hanya mendaftarkan pendengar dengan EA dan menjalankan respons yang sesuai. Tetapi itu adalah skenario lanjutan yang membutuhkan waktu untuk berkembang. Saya katakan mulai dengan fasad pemersatu dan pergi dari sana.
sumber
Mengapa tidak menggabungkan keduanya?
Buat fasad dan letakkan semua layanan yang digunakan oleh viewmodels Anda. Maka Anda dapat memiliki fasad tunggal untuk semua model Anda tanpa kata S buruk.
Atau Anda bisa menggunakan injeksi properti alih-alih injeksi konstruktor. Tapi kemudian, Anda perlu memastikan bahwa mereka disuntik dengan benar.
sumber