Saya minta maaf untuk pertanyaan yang panjang, ini sedikit berbunyi kata-kata kasar, tapi saya berjanji tidak! Saya telah merangkum pertanyaan saya di bawah
Di dunia MVC, banyak hal langsung. Model memiliki status, View menunjukkan Model, dan Controller melakukan hal - hal ke / dengan Model (pada dasarnya), controller tidak memiliki status. Untuk melakukan hal-hal Controller memiliki beberapa dependensi pada layanan web, repositori, lot. Ketika Anda instantiate controller Anda peduli tentang penyediaan dependensi itu, tidak ada yang lain. Ketika Anda menjalankan suatu tindakan (metode pada Kontroler), Anda menggunakan dependensi itu untuk mengambil atau memperbarui Model atau memanggil beberapa layanan domain lainnya. Jika ada konteks apa pun, katakanlah seperti beberapa pengguna ingin melihat detail item tertentu, Anda meneruskan ID item itu sebagai parameter ke Action. Tidak ada tempat di Controller ada referensi ke negara. Sejauh ini baik.
Masukkan MVVM. Saya suka WPF, saya suka pengikatan data. Saya suka kerangka kerja yang membuat pengikatan data ke ViewModels lebih mudah (menggunakan Caliburn Micro atm). Saya merasa hal-hal yang kurang langsung di dunia ini. Mari kita lakukan latihan lagi: Model memiliki negara, View menunjukkan ViewModel, dan ViewModel melakukan hal-hal untuk / dengan Model (pada dasarnya), ViewModel tidak memiliki negara! (untuk mengklarifikasi; mungkin itu mendelegasikan semua properti ke satu atau lebih Model, tetapi itu berarti ia harus memiliki referensi ke model dengan satu cara atau yang lain, yang merupakan keadaan itu sendiri) Untuk melakukanbarang yang ViewModel memiliki beberapa ketergantungan pada layanan web, repositori, banyak. Ketika Anda instantiate ViewModel Anda peduli tentang penyediaan dependensi tersebut, tetapi juga negara. Dan ini, tuan dan nyonya, mengganggu saya tanpa akhir.
Setiap kali Anda perlu instantiate ProductDetailsViewModel
dari ProductSearchViewModel
(dari mana Anda memanggil ProductSearchWebService
yang pada gilirannya kembali IEnumerable<ProductDTO>
, semua orang masih bersama saya?), Anda dapat melakukan salah satu dari ini:
- panggilan
new ProductDetailsViewModel(productDTO, _shoppingCartWebService /* dependcy */);
, ini buruk, bayangkan 3 dependensi lebih, ini berartiProductSearchViewModel
kebutuhan untuk mengambil dependensi itu juga. Mengubah konstruktor juga menyakitkan. - sebut
_myInjectedProductDetailsViewModelFactory.Create().Initialize(productDTO);
, pabrik hanyalah sebuah Func, mereka mudah dihasilkan oleh sebagian besar kerangka kerja IoC. Saya pikir ini buruk karena metode Init adalah abstraksi yang bocor. Anda juga tidak dapat menggunakan kata kunci hanya baca untuk bidang yang diatur dalam metode Init. Saya yakin ada beberapa alasan lagi. - sebut
_myInjectedProductDetailsViewModelAbstractFactory.Create(productDTO);
So ... ini adalah pola (pabrik abstrak) yang biasanya direkomendasikan untuk masalah jenis ini. Saya pikir itu jenius karena memuaskan keinginan saya untuk mengetik statis, sampai saya benar-benar mulai menggunakannya. Jumlah kode boilerplate saya pikir terlalu banyak (Anda tahu, terlepas dari nama variabel konyol yang saya gunakan). Untuk setiap ViewModel yang membutuhkan parameter runtime Anda akan mendapatkan dua file tambahan (antarmuka pabrik dan implementasi), dan Anda perlu mengetikkan dependensi non-runtime seperti 4 kali tambahan. Dan setiap kali dependensi berubah, Anda juga bisa mengubahnya di pabrik. Rasanya seperti saya bahkan tidak menggunakan wadah DI lagi. (Saya pikir Castle Windsor memiliki beberapa solusi untuk ini [dengan kekurangannya sendiri, koreksi saya jika saya salah]). - lakukan sesuatu dengan jenis atau kamus anonim. Saya suka mengetik statis.
Jadi ya. Mencampuradukkan keadaan dan perilaku dengan cara ini menciptakan masalah yang tidak ada sama sekali di MVC. Dan saya merasa saat ini tidak ada solusi yang cukup memadai untuk masalah ini. Sekarang saya ingin mengamati beberapa hal:
- Orang-orang benar-benar menggunakan MVVM. Jadi mereka tidak peduli dengan semua hal di atas, atau mereka memiliki solusi cemerlang lainnya.
- Saya belum menemukan contoh mendalam MVVM dengan WPF. Sebagai contoh, proyek sampel NDDD sangat membantu saya memahami beberapa konsep DDD. Saya sangat suka jika seseorang bisa mengarahkan saya ke arah yang mirip dengan MVVM / WPF.
- Mungkin saya melakukan kesalahan MVVM dan saya harus membalikkan desain saya. Mungkin saya seharusnya tidak memiliki masalah ini sama sekali. Yah saya tahu orang lain telah mengajukan pertanyaan yang sama jadi saya pikir saya bukan satu-satunya.
Untuk meringkas
- Apakah saya benar menyimpulkan bahwa memiliki ViewModel menjadi titik integrasi untuk kedua negara dan perilaku adalah alasan untuk beberapa kesulitan dengan pola MVVM secara keseluruhan?
- Apakah menggunakan pola abstrak pabrik satu-satunya / cara terbaik untuk instantiate ViewModel dengan cara yang diketik secara statis?
- Apakah ada sesuatu seperti implementasi referensi mendalam yang tersedia?
- Apakah memiliki banyak ViewModels dengan kedua status / perilaku bau desain?
Jawaban:
Masalah dependensi saat memulai model tampilan baru dapat ditangani dengan IOC.
Saat menyiapkan wadah ...
Saat Anda membutuhkan model tampilan Anda:
Ketika menggunakan kerangka kerja seperti caliburn micro, seringkali sudah ada beberapa bentuk wadah IOC.
sumber
Saya bekerja setiap hari dengan ASP.NET MVC dan telah bekerja di WPF selama lebih dari setahun dan ini adalah bagaimana saya melihatnya:
MVC
Kontroler seharusnya mengatur aksi (ambil ini, tambahkan itu).
Tampilan bertanggung jawab untuk menampilkan model.
Model ini biasanya mencakup data (mis. UserId, FirstName) dan juga status (mis. Judul) dan biasanya khusus tampilan.
MVVM
Model biasanya hanya menyimpan data (mis. UserId, FirstName) dan biasanya diedarkan
Model tampilan mencakup perilaku tampilan (metode), datanya (model) dan interaksi (perintah) - mirip dengan pola MVP aktif di mana presenter mengetahui model tersebut. Model tampilan adalah tampilan spesifik (1 tampilan = 1 model tampilan).
Tampilan bertanggung jawab untuk menampilkan data dan pengikatan data ke model tampilan. Ketika sebuah view dibuat, biasanya model view yang terkait dibuat dengannya.
Yang harus Anda ingat adalah bahwa pola presentasi MVVM khusus untuk WPF / Silverlight karena sifat pengikatan datanya.
Tampilan biasanya tahu model tampilan mana yang terkait (atau abstraksi).
Saya akan menyarankan Anda memperlakukan model tampilan sebagai singleton, meskipun itu instantiated per view. Dengan kata lain, Anda harus dapat membuatnya melalui DI melalui wadah IOC dan memanggil metode yang tepat untuk mengatakannya; memuat modelnya berdasarkan parameter. Sesuatu seperti ini:
Sebagai contoh dalam kasus ini, Anda tidak akan membuat model tampilan khusus untuk pengguna yang diperbarui - sebaliknya model akan berisi data spesifik pengguna yang akan dimuat melalui beberapa panggilan pada model tampilan.
sumber
Jawaban singkat untuk pertanyaan Anda:
Versi panjang:
Kami menghadapi Masalah yang sama, dan menemukan beberapa hal yang dapat membantu Anda. Meskipun saya tidak tahu solusi "ajaib", hal-hal itu sedikit meredakan rasa sakit.
Terapkan model yang dapat diikat dari DTO untuk pelacakan perubahan dan validasi. "Data" -ViewModels itu tidak boleh bergantung pada layanan dan tidak berasal dari wadah. Mereka bisa saja "baru" ditingkatkan, diedarkan dan bahkan dapat diturunkan dari DTO. Bottomline adalah untuk mengimplementasikan Model khusus untuk aplikasi Anda (Seperti MVC).
Decouple ViewModels Anda. Caliburn membuatnya mudah untuk memasangkan ViewModels bersama. Ia bahkan menyarankannya melalui model Layar / Konduktornya. Tetapi penggabungan ini membuat ViewModels sulit untuk diuji unit, membuat banyak dependensi dan yang paling penting: Membebankan beban mengelola siklus hidup ViewModel pada ViewModels Anda. Salah satu cara untuk memisahkan mereka adalah menggunakan sesuatu seperti layanan navigasi atau pengontrol ViewModel. Misalnya
antarmuka publik IShowViewModels {void Show (objek inlineArgumentsAsAnonymousType, string regionId); }
Bahkan lebih baik melakukan ini dengan beberapa bentuk pesan. Tetapi yang penting adalah tidak menangani siklus hidup ViewModel dari ViewModels lainnya. Dalam MVC Controllers tidak saling bergantung, dan dalam MVVM ViewModels tidak boleh saling bergantung. Integrasikan mereka melalui beberapa cara lain.
INeedData<T1,T2,...>
dan menegakkan parameter penciptaan aman-jenis, itu tidak layak. Juga membuat pabrik untuk setiap jenis ViewModel tidak sepadan. Sebagian besar Kontainer IoC memberikan solusi untuk ini. Anda akan mendapatkan kesalahan saat runtime tetapi de-coupling dan unit testability sepadan. Anda masih melakukan semacam tes integrasi dan kesalahan-kesalahan itu terlihat dengan mudah.sumber
Cara saya biasanya melakukan ini (menggunakan PRISM), adalah setiap perakitan berisi modul inisialisasi wadah, di mana semua antarmuka, contoh terdaftar pada startup.
Dan dengan contoh kelas Anda, akan dilaksanakan seperti ini, dengan wadah yang dilaluinya. Dengan cara ini setiap dependensi baru dapat ditambahkan dengan mudah karena Anda sudah memiliki akses ke wadah.
Sangat umum untuk memiliki kelas ViewModelBase, dari mana semua model tampilan Anda berasal, yang berisi referensi ke wadah. Selama Anda terbiasa menyelesaikan semua model tampilan alih-alih
new()'ing
mereka, itu harus membuat semua resolusi ketergantungan jauh lebih sederhana.sumber
Terkadang lebih baik untuk pergi ke definisi paling sederhana daripada contoh lengkap: http://en.wikipedia.org/wiki/Model_View_ViewModel mungkin membaca contoh ZK Java lebih mencerahkan daripada C # satu.
Lain kali dengarkan insting Anda ...
Apakah model Anda objek per pemetaan tabel? Mungkin ORM akan membantu pemetaan ke objek domain saat menangani bisnis atau memperbarui beberapa tabel.
sumber