कैसे रनटाइम में दृश्यमॉडल बनाने के लिए कम दर्दनाक


17

मैं लंबे सवाल के लिए माफी माँगता हूँ, यह एक शेख़ी के रूप में थोड़ा पढ़ता है, लेकिन मैं वादा करता हूँ कि यह नहीं है! मैंने अपना प्रश्न नीचे प्रस्तुत किया है

एमवीसी दुनिया में, चीजें सीधी होती हैं। मॉडल में राज्य है, दृश्य मॉडल दिखाता है, और नियंत्रक मॉडल (मूल रूप से) के साथ सामान करता है , एक नियंत्रक की कोई स्थिति नहीं है। करने के लिए कर सामान नियंत्रक वेब सेवाओं, भंडार, बहुत पर कुछ निर्भरता है। जब आप किसी कंट्रोलर को इंस्टेंट करते हैं तो आप उन निर्भरताओं की आपूर्ति के बारे में परवाह करते हैं, और कुछ नहीं। जब आप किसी क्रिया (नियंत्रक पर विधि) को निष्पादित करते हैं, तो आप उन निर्भरता का उपयोग करके मॉडल को पुनः प्राप्त करने या अपडेट करने या किसी अन्य डोमेन सेवा को कॉल करने के लिए उपयोग करते हैं। यदि कोई संदर्भ है, तो कहें कि कुछ उपयोगकर्ता किसी विशेष आइटम का विवरण देखना चाहते हैं, आप कार्रवाई के पैरामीटर के रूप में उस आइटम की आईडी पास करते हैं। नियंत्रक में कहीं भी किसी भी राज्य के लिए कोई संदर्भ नहीं है। अब तक सब ठीक है।

MVVM दर्ज करें। मुझे WPF पसंद है, मुझे डेटा बाइंडिंग बहुत पसंद है। मुझे ऐसे फ्रेमवर्क पसंद हैं जो ViewModels के लिए डेटा बाइंडिंग को और भी आसान बनाते हैं (Caliburn Micro atm का उपयोग करके)। मुझे लगता है कि इस दुनिया में चीजें कम सीधी हैं। चलो व्यायाम फिर से: मॉडल राज्य, देखें है शो ViewModel, और ViewModel करता मॉडल (मूल रूप से) के साथ / करने के लिए सामान, एक ViewModel करता राज्य है! (स्पष्ट करने के लिए, शायद यह एक या अधिक मॉडल के प्रतिनिधियों सभी गुण हैं, लेकिन वह साधन यह मॉडल एक तरह से या किसी अन्य, जो अपने आप में राज्य है के लिए एक संदर्भ होना आवश्यक है) करने के लिए करते हैंViewModel में वेब सेवाओं, भंडार, बहुत कुछ पर निर्भरताएं हैं। जब आप एक ViewModel को इंस्टेंट करते हैं, तो आप उन निर्भरताओं की आपूर्ति के बारे में परवाह करते हैं, लेकिन राज्य भी। और यह, देवियों और सज्जनों, मुझे कोई अंत नहीं है।

जब भी आपको इसमें ProductDetailsViewModelसे ProductSearchViewModel(जिसमें से आपने कॉल किया था, ProductSearchWebServiceजिसे IEnumerable<ProductDTO>हर कोई अभी भी मेरे पास है?) से इन्स्टैंट करने की जरूरत है , तो आप इनमें से एक काम कर सकते हैं:

  • कॉल new ProductDetailsViewModel(productDTO, _shoppingCartWebService /* dependcy */);, यह बुरा है, 3 अधिक निर्भरता की कल्पना करें , इसका मतलब ProductSearchViewModelउन निर्भरताओं को भी लेने की आवश्यकता है। इसके अलावा कंस्ट्रक्टर को बदलना दर्दनाक है।
  • कॉल _myInjectedProductDetailsViewModelFactory.Create().Initialize(productDTO);, कारखाने सिर्फ एक फंक है, वे आसानी से अधिकांश आईओसी ढांचे द्वारा उत्पन्न होते हैं। मुझे लगता है कि यह बुरा है क्योंकि Init विधियां एक टपका हुआ अमूर्त है। आप उन क्षेत्रों के लिए भी आसानी से कीवर्ड का उपयोग नहीं कर सकते हैं जो इनिट विधि में सेट किए गए हैं। मुझे यकीन है कि कुछ और कारण हैं।
  • _myInjectedProductDetailsViewModelAbstractFactory.Create(productDTO);तो कॉल करें ... यह पैटर्न (अमूर्त कारखाना) है जिसे आमतौर पर इस प्रकार की समस्या के लिए अनुशंसित किया जाता है। यद्यपि यह वास्तव में इसका उपयोग करने की मेरी लालसा को संतुष्ट करता है, जब तक कि मैं वास्तव में इसका उपयोग करना शुरू नहीं करता, यह प्रतिभा थी। बॉयलरप्लेट कोड की मात्रा मुझे लगता है कि बहुत अधिक है (आप जानते हैं कि हास्यास्पद चर नामों के अलावा मुझे उपयोग मिलता है)। प्रत्येक ViewModel के लिए जो रनटाइम मापदंडों की आवश्यकता होती है, आपको दो अतिरिक्त फ़ाइलें (फ़ैक्टरी इंटरफ़ेस और कार्यान्वयन) मिलेंगी, और आपको 4 अतिरिक्त समय की तरह नॉन-रनटाइम निर्भरताएँ टाइप करनी होंगी। और हर बार जब निर्भरता बदलती है, तो आपको इसे कारखाने में भी बदलना होगा। ऐसा महसूस होता है कि मैं अब DI कंटेनर का उपयोग नहीं करता। (मुझे लगता है कि कैसल विंडसर के पास इसके लिए कुछ प्रकार का समाधान है [इसके साथ अपनी कमियां हैं, मुझे सही करें अगर मैं गलत हूं])।
  • अनाम प्रकार या शब्दकोश के साथ कुछ करें। मुझे अपनी स्टैटिक टाइपिंग पसंद है।

तो हाँ। इस तरह से राज्य और व्यवहार को मिलाने से एक समस्या पैदा होती है जो MVC में बिल्कुल भी मौजूद नहीं है। और मुझे लगता है कि वर्तमान में इस समस्या के लिए वास्तव में पर्याप्त समाधान नहीं है। अब मैं कुछ चीजों का पालन करना चाहता हूं:

  • लोग वास्तव में MVVM का उपयोग करते हैं। इसलिए वे या तो उपरोक्त सभी के बारे में परवाह नहीं करते हैं, या उनके पास कुछ शानदार अन्य समाधान हैं।
  • मुझे WPF के साथ MVVM का गहन उदाहरण नहीं मिला है। उदाहरण के लिए, NDDD- नमूना परियोजना ने मुझे कुछ DDD अवधारणाओं को समझने में बहुत मदद की। मैं वास्तव में इसे पसंद करूंगा अगर कोई मुझे MVVM / WPF के लिए कुछ समान दिशा में इंगित कर सके।
  • शायद मैं MVVM को गलत कर रहा हूं और मुझे अपने डिजाइन को उल्टा करना चाहिए। शायद मुझे यह समस्या बिल्कुल नहीं होनी चाहिए। वैसे मुझे पता है कि अन्य लोगों ने भी यही सवाल पूछा है, इसलिए मुझे लगता है कि मैं अकेला नहीं हूं।

संक्षेप में

  • क्या मैं यह निष्कर्ष निकालने के लिए सही हूं कि ViewModel का राज्य और व्यवहार दोनों के लिए एक एकीकरण बिंदु है और एक पूरे के रूप में MVVM पैटर्न के साथ कुछ कठिनाइयों का कारण है?
  • अमूर्त कारखाने पैटर्न का उपयोग केवल / सर्वोत्तम तरीके से एक ViewModel को सांख्यिकीय रूप से टाइप करने के लिए किया गया है?
  • क्या गहन संदर्भ कार्यान्वयन में ऐसा कुछ उपलब्ध है?
  • दोनों राज्य / व्यवहार के साथ एक डिजाइन गंध के साथ बहुत सारे ViewModels रहा है?

10
यह पढ़ने के लिए बहुत लंबा है, संशोधन पर विचार करें, वहां बहुत अधिक अप्रासंगिक सामान है। आप अच्छे उत्तर याद कर सकते हैं क्योंकि लोग उस सब को पढ़ने के लिए परेशान नहीं होंगे।
यानिस

आपने कहा कि आप कैलिबर्न.माइक्रो से प्यार करते हैं, फिर भी आप नहीं जानते कि यह ढांचा नए दृश्य मॉडल को कैसे गति दे सकता है? इसके कुछ उदाहरण देखें।
यूफोरिक

@ यदि आप कुछ अधिक विशिष्ट हो सकते हैं, तो Google मुझे यहां मदद करने के लिए नहीं लगता है। कुछ खोजशब्द मिले जिन्हें मैं खोज सकता था?
DVDvorle

3
मुझे लगता है कि आप एमवीसी को थोड़ा सरल कर रहे हैं। सुनिश्चित करें कि शुरुआत में मॉडल दिखाता है, लेकिन ऑपरेशन के दौरान यह राज्य बदल रहा है। यह बदलती स्थिति, मेरी राय में, "एडिट मॉडल" है। यही है, कम स्थिरता प्रतिबंधों के साथ मॉडल का एक चपटा संस्करण। वास्तव में, जिसे मैं एडिट मॉडल कहता हूं वह MVVM ViewModel है। यह संक्रमण के दौरान राज्य को धारण करता है, जो पहले MVC में View द्वारा आयोजित किया गया था, या मॉडल के एक अनछुए संस्करण में वापस धकेल दिया गया, जहां मुझे नहीं लगता कि यह संबंधित है। तो आप पहले "प्रवाह में" राज्य था। अब यह सभी ViewModel में है।
स्कॉट व्हिटलॉक

@ScottWhitlock मैं वास्तव में MVC को सरल बना रहा हूं। लेकिन मैं यह नहीं कह रहा कि यह गलत है कि राज्य "फ्लक्स" में ViewModel है, मैं कह रहा हूं कि वहां के व्यवहार को कम करने के साथ-साथ ViewModel को एक और ViewModel से प्रयोग करने योग्य अवस्था में प्रारंभ करना कठिन बना देता है। एमवीसी में आपका "एडिट मॉडल" खुद को बचाने का तरीका नहीं जानता (इसमें सेव विधि नहीं है)। लेकिन नियंत्रक यह जानता है, और ऐसा करने के लिए आवश्यक सभी निर्भरताएं हैं।
16

जवाबों:


2

एक नए दृश्य मॉडल की शुरुआत करते समय निर्भरता का मुद्दा IOC के साथ संभाला जा सकता है।

public class MyCustomViewModel{
  private readonly IShoppingCartWebService _cartService;

  private readonly ITimeService _timeService;

  public ProductDTO ProductDTO { get; set; }

  public ProductDetailsViewModel(IShoppingCartWebService cartService, ITimeService timeService){
    _cartService = cartService;
    _timeService = timeService;
  }
}

जब कंटेनर की स्थापना ...

Container.Register<IShoppingCartWebService,ShoppingCartWebSerivce>().As.Singleton();
Container.Register<ITimeService,TimeService>().As.Singleton();
Container.Register<ProductDetailsViewModel>();

जब आपको अपने विचार मॉडल की आवश्यकता हो:

var viewmodel = Container.Resolve<ProductDetailsViewModel>();
viewmodel.ProductDTO = myProductDTO;

कैलीबर्न माइक्रो जैसे ढांचे का उपयोग करते समय अक्सर आईओसी कंटेनर का कोई न कोई रूप पहले से मौजूद होता है।

SomeCompositionView view = new SomeCompositionView();
ISomeCompositionViewModel viewModel = IoC.Get<ISomeCompositionViewModel>();
ViewModelBinder.Bind(viewModel, view, null);

1

मैं ASP.NET MVC के साथ दैनिक कार्य करता हूं और एक WPF पर एक वर्ष से अधिक काम किया है और यह है कि मैं इसे कैसे देखता हूं:

MVC

नियंत्रक को ऑर्केस्ट्रा क्रियाओं के लिए माना जाता है (इसे जोड़ें, इसे जोड़ें)।

मॉडल प्रदर्शित करने के लिए दृश्य जिम्मेदार है।

मॉडल आमतौर पर डेटा (उदाहरण। UserId, FirstName) के साथ-साथ राज्य (उदाहरण। टाइटल) को शामिल करता है और आमतौर पर विशिष्ट होता है।

MVVM

मॉडल में आमतौर पर केवल डेटा (उदा। UserId, FirstName) होता है और इसे आमतौर पर पास किया जाता है

दृश्य मॉडल दृश्य (विधियों), उसके डेटा (मॉडल) और इंटरैक्शन (कमांड) के व्यवहार को शामिल करता है - सक्रिय एमवीपी पैटर्न के समान जहां प्रस्तुतकर्ता मॉडल से अवगत है। दृश्य मॉडल विशिष्ट है (1 दृश्य = 1 दृश्य मॉडल)।

दृश्य मॉडल के लिए डेटा और डेटा-बाइंडिंग प्रदर्शित करने के लिए दृश्य जिम्मेदार है। जब कोई दृश्य बनाया जाता है, तो आमतौर पर उसका संबद्ध दृश्य मॉडल उसके साथ बनाया जाता है।


आपको जो याद रखना चाहिए वह यह है कि MVVM प्रस्तुति पैटर्न WPF / सिल्वरलाइट उनके डेटा-बाइंडिंग प्रकृति के कारण विशिष्ट है।

दृश्य आमतौर पर जानता है कि कौन सा मॉडल इसके साथ जुड़ा हुआ है (या एक का एक अमूर्त)।

मैं आपको सलाह दूंगा कि आप दृश्य मॉडल को एक सिंगलटन के रूप में मानें, भले ही यह प्रति दृश्य तात्कालिक हो। दूसरे शब्दों में, आपको IOC कंटेनर के माध्यम से DI के माध्यम से इसे बनाने में सक्षम होना चाहिए और यह कहने के लिए उपयुक्त तरीकों को कॉल करना चाहिए; मापदंडों के आधार पर इसके मॉडल को लोड करें। कुछ इस तरह:

public partial class EditUserView
{
    public EditUserView(IContainer container, int userId) : this() {
        var viewModel = container.Resolve<EditUserViewModel>();
        viewModel.LoadModel(userId);
        DataContext = viewModel;
    }
}

इस मामले में एक उदाहरण के रूप में, आप अपडेट किए जा रहे उपयोगकर्ता के लिए एक विशिष्ट मॉडल नहीं बनाएंगे - इसके बजाय मॉडल में उपयोगकर्ता विशिष्ट डेटा होगा जो दृश्य मॉडल पर कुछ कॉल के माध्यम से लोड हो जाता है।


यदि मेरा FirstName "पीटर" है और मेरे टाइटल {"Rev", "Dr"} * हैं, तो आप FirstName डेटा और शीर्षक स्थिति को क्यों मानते हैं? या आप अपने उदाहरण को स्पष्ट कर सकते हैं? * वास्तव में नहीं
पीट किर्कम

@PeteKirkham - 'टाइटल्स' उदाहरण मैं एक कॉम्बोक्स कहने के संदर्भ में उल्लेख कर रहा था। आम तौर पर जब आप सूचना भेजते हैं, तो आप राज्य को नहीं भेजेंगे (उदाहरण के लिए राज्यों / प्रांतों / शीर्षकों की एक सूची) जिसका उपयोग चयन करने के लिए किया गया था। डेटा के साथ स्थानांतरित करने के लिए किसी भी सार्थक राज्य (उदाहरण के लिए उपयोग में उपयोगकर्ता नाम) को प्रसंस्करण के बिंदु पर जांचना चाहिए क्योंकि राज्य बासी हो सकता है (यदि आप कुछ अतुल्यकालिक पैटर्न जैसे संदेश कतारबद्ध का उपयोग कर रहे थे)।
शेलकेल

हालाँकि इस पोस्ट को दो साल हो चुके हैं, मुझे भविष्य के दर्शकों के पक्ष में एक टिप्पणी करनी चाहिए: दो बातों ने मुझे आपके उत्तर से विचलित कर दिया। एक दृश्य शायद एक ViewModel से मेल खाता है, लेकिन एक ViewModel को कई दृश्यों द्वारा दर्शाया जा सकता है। दूसरे, आप जो वर्णन कर रहे हैं वह सेवा लोकेटर विरोधी पैटर्न है। IMHO आप सीधे हर जगह viewmodels को हल नहीं करना चाहिए। यही डीआई के लिए है। अपने संकल्पों को कम बिंदुओं पर हल करें जैसा कि आप कर सकते हैं। उदाहरण के लिए, कैलीबर्न को आपके लिए यह काम करने दें।
जॉनी एडमिट

1

आपके प्रश्नों के लिए संक्षिप्त उत्तर:

  1. हाँ राज्य + व्यवहार उन समस्याओं की ओर जाता है, लेकिन यह सभी OO के लिए सही है। असली अपराधी ViewModels का युग्मन है जो एक प्रकार का SRP उल्लंघन है।
  2. स्टेटिकली टाइप्ड, शायद। लेकिन आपको ViewModels को अन्य ViewModels से तुरंत हटाने की अपनी आवश्यकता को कम / समाप्त करना चाहिए।
  3. ऐसा नहीं है कि मैं जागरूक हूं।
  4. नहीं, लेकिन असंबंधित राज्य और व्यवहार वाले ViewModels (जैसे कुछ मॉडल संदर्भ और कुछ ViewModel संदर्भ)

लंबा संस्करण:

हम एक ही समस्या का सामना कर रहे हैं, और कुछ चीजें मिली हैं जो आपकी मदद कर सकती हैं। हालांकि मुझे "जादू" समाधान नहीं पता है, लेकिन वे चीजें दर्द को कम कर रही हैं।

  1. ट्रैकिंग और सत्यापन को बदलने के लिए डीटीओ से बाइंडेबल मॉडल लागू करें। उन "डेटा" -ViewModels को सेवाओं पर निर्भर नहीं होना चाहिए और कंटेनर से नहीं आना चाहिए। वे सिर्फ "नए" एड हो सकते हैं, चारों ओर पारित हो सकते हैं और डीटीओ से भी प्राप्त हो सकते हैं। बॉटमलाइन आपके आवेदन के लिए एक आदर्श मॉडल लागू करना है (जैसे एमवीसी)।

  2. अपने ViewModels को कम करें। Caliburn, ViewModels को एक साथ जोड़ना आसान बनाता है। यह अपने स्क्रीन / कंडक्टर मॉडल के माध्यम से भी इसका सुझाव देता है। लेकिन यह युग्मन ViewModels को इकाई परीक्षण के लिए कठिन बनाता है, बहुत अधिक निर्भरता और सबसे महत्वपूर्ण बनाता है: आपके ViewModels पर ViewModel के जीवनचक्र के प्रबंधन के भार का प्रस्ताव करता है। उन्हें डिकूप करने का एक तरीका नेविगेशन सेवा या व्यूमॉडल नियंत्रक की तरह कुछ का उपयोग करना है। उदाहरण के लिए

    सार्वजनिक इंटरफ़ेस IShowViewModels {शून्य दिखाएँ (ऑब्जेक्ट inlineArgumentsAsAnonymType, string areaId); }

इससे भी बेहतर यह है कि किसी तरह के मैसेजिंग के जरिए ऐसा किया जाए। लेकिन महत्वपूर्ण बात ViewModel जीवन चक्र को अन्य ViewModels से संभालना नहीं है। एमवीसी में कंट्रोलर एक दूसरे पर निर्भर नहीं होते हैं, और एमवीवीएम में ViewModels एक दूसरे पर निर्भर नहीं होना चाहिए। उन्हें कुछ अन्य तरीकों से एकीकृत करें।

  1. अपने कंटेनरों का उपयोग "कड़ाई" -टाइप / गतिशील सुविधाओं के साथ करें। यद्यपि यह संभव हो सकता है कुछ INeedData<T1,T2,...>प्रकार की रचना करना और प्रकार-सुरक्षित निर्माण मापदंडों को लागू करना, यह इसके लायक नहीं है। इसके अलावा प्रत्येक ViewModel प्रकार के लिए कारखाने बनाना इसके लायक नहीं है। अधिकांश IoC कंटेनर इसका समाधान प्रदान करते हैं। आपको रनटाइम पर त्रुटियां मिलेंगी, लेकिन डी-कपलिंग और यूनिट टेस्टिबिलिटी इसके लायक है। आप अभी भी किसी प्रकार का एकीकरण परीक्षण करते हैं और उन त्रुटियों को आसानी से देखा जाता है।

0

जिस तरह से मैं आमतौर पर ऐसा करता हूं (PRISM का उपयोग करके), प्रत्येक असेंबली में एक कंटेनर इनिशियलाइज़ेशन मॉड्यूल होता है, जहां सभी इंटरफेस, उदाहरण स्टार्टअप पर पंजीकृत होते हैं।

private void RegisterResources()
{
    Container.RegisterType<IDataService, DataService>();
    Container.RegisterType<IProductSearchViewModel, ProductSearchViewModel>();
    Container.RegisterType<IProductDetailsViewModel, ProductDetailsViewModel>();
}

और अपने उदाहरण वर्गों को देखते हुए, इस तरह से लागू किया जाएगा, जिसमें कंटेनर को सभी तरह से पारित किया जाएगा। इस तरह किसी भी नई निर्भरता को आसानी से जोड़ा जा सकता है क्योंकि आपके पास पहले से ही कंटेनर है।

/// <summary>
/// IDataService Interface
/// </summary>
public interface IDataService
{
    DataTable GetSomeData();
}

public class DataService : IDataService
{
    public DataTable GetSomeData()
    {
        MessageBox.Show("This is a call to the GetSomeData() method.");

        var someData = new DataTable("SomeData");
        return someData;
    }
}

public interface IProductSearchViewModel
{
}

public class ProductSearchViewModel : IProductSearchViewModel
{
    private readonly IUnityContainer _container;

    /// <summary>
    /// This will get resolved if it's been added to the container.
    /// Or alternately you could use constructor resolution. 
    /// </summary>
    [Dependency]
    public IDataService DataService { get; set; }

    public ProductSearchViewModel(IUnityContainer container)
    {
        _container = container;
    }

    public void SearchAndDisplay()
    {
        DataTable results = DataService.GetSomeData();

        var detailsViewModel = _container.Resolve<IProductDetailsViewModel>();
        detailsViewModel.DisplaySomeDataInView(results);

        // Create the view, usually resolve using region manager etc.
        var detailsView = new DetailsView() { DataContext = detailsViewModel };
    }
}

public interface IProductDetailsViewModel
{
    void DisplaySomeDataInView(DataTable dataTable);
}

public class ProductDetailsViewModel : IProductDetailsViewModel
{
    private readonly IUnityContainer _container;

    public ProductDetailsViewModel(IUnityContainer container)
    {
        _container = container;
    }

    public void DisplaySomeDataInView(DataTable dataTable)
    {
    }
}

ViewModelBase क्लास होना काफी आम है, जो आपके सभी व्यू मॉडल से प्राप्त होता है, जिसमें कंटेनर का संदर्भ होता है। जब तक आप new()'ingउनके बजाय सभी दृश्य मॉडल को हल करने की आदत में आते हैं, तब तक यह सभी निर्भरता के समाधान को बहुत सरल बना देना चाहिए।


0

कभी-कभी पूर्ण-विकसित उदाहरण के बजाय सरलतम परिभाषा पर जाना अच्छा होता है: http://en.wikipedia.org/wiki/Model_View_ViewModel शायद ZK जावा उदाहरण पढ़ना C / a की तुलना में अधिक रोशन है।

अन्य बार अपने पेट वृत्ति को सुनो ...

दोनों राज्य / व्यवहार के साथ एक डिजाइन गंध के साथ बहुत सारे ViewModels रहा है?

क्या आपके मॉडल प्रति टेबल मैपिंग पर ऑब्जेक्ट हैं? शायद एक ORM व्यवसाय को संभालने या कई तालिकाओं को अपडेट करते समय डोमेन ऑब्जेक्ट को मैप करने में मदद करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.