MVVM और सेवा पैटर्न


14

मैं MVVM पैटर्न का उपयोग करके WPF एप्लिकेशन बना रहा हूं। अभी, मेरे व्यूअमॉडल्स मॉडल को पुनः प्राप्त करने के लिए सर्विस लेयर को कॉल करते हैं (कैसे व्यूमॉडल के लिए प्रासंगिक नहीं है) और उन्हें व्यूमॉडल में परिवर्तित करें। मैं व्यूमोडेल के लिए आवश्यक सेवा पास करने के लिए कंस्ट्रक्टर इंजेक्शन का उपयोग कर रहा हूं।

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

मैं कुछ समाधान सोच रहा हूँ:

  1. सभी उपलब्ध सेवाओं वाले इंटरफेस के रूप में एक सेवा सिंगलटन (IServices) बनाना। उदाहरण: Services.Current.XXXService.Retrieve (), Services.Current.YYYService.Retrieve ()। इस तरह, मेरे पास उन सेवाओं के एक टन के साथ एक विशाल निर्माता नहीं है।

  2. ViewModel द्वारा उपयोग की जाने वाली सेवाओं के लिए एक पहलू बनाना और मेरे viewmodel के ctor में इस ऑब्जेक्ट को पास करना। लेकिन फिर, मुझे अपने कॉम्प्लेक्स व्यूमोडल्स में से प्रत्येक के लिए एक मुखौटा बनाना होगा, और यह थोड़ा अधिक हो सकता है ...

आपको क्या लगता है कि इस तरह की वास्तुकला को लागू करने का "सही" तरीका है?


मुझे लगता है कि ऐसा करने का "सही" तरीका एक अलग परत बनाना है जो सेवाओं को कॉल करता है और व्यूमेल बनाने के लिए जो भी कास्टिंग आवश्यक है वह करता है। अपने ViewModels को स्वयं बनाने के लिए ज़िम्मेदार नहीं होना चाहिए।
एमी ब्लैंकेनशिप

@AmyBlankenship: देखें मॉडल को खुद को बनाने के लिए (या यहां तक ​​कि आवश्यक रूप से सक्षम होने के लिए) नहीं होना चाहिए, लेकिन अनिवार्य रूप से कभी-कभी अन्य दृश्य मॉडल बनाने के लिए जिम्मेदार होगा । ऑटोमैटिक-फैक्ट्री सपोर्ट वाला आईओसी कंटेनर यहां बहुत बड़ी मदद है।
Aaronaught

"कभी-कभी होगा" और "चाहिए" दो अलग-अलग जानवर हैं;)
एमी ब्लैंकेनशिप

@AmyBlankenship: क्या आप यह सुझाव दे रहे हैं कि व्यू मॉडल को अन्य व्यू मॉडल नहीं बनाना चाहिए? यह निगलने के लिए एक कठिन गोली है। मैं यह कहते हुए समझ सकता हूं कि व्यू मॉडल्स को newअन्य व्यू मॉडल बनाने के लिए उपयोग नहीं करना चाहिए , लेकिन एमडीआई एप्लिकेशन के रूप में कुछ के बारे में सोचें जहां "नए दस्तावेज़" बटन या मेनू पर क्लिक करने से एक नया टैब जुड़ जाएगा या एक नई विंडो खुल जाएगी। शेल / कंडक्टर को किसी चीज के नए उदाहरण बनाने में सक्षम होना चाहिए , भले ही वह अप्रत्यक्ष की एक या कुछ परतों के पीछे छिपा हो।
हारून

ठीक है, निश्चित रूप से यह अनुरोध करने की क्षमता होनी चाहिए कि एक दृश्य कहीं बनाया जाए। लेकिन इसे खुद बनाना है? मेरी दुनिया में नहीं :)। लेकिन फिर मैं जिस दुनिया में रहता हूं, हम वीएम को "प्रेजेंटेशन मॉडल" कहते हैं।
एमी ब्लैंकेनशिप

जवाबों:


22

वास्तव में, ये दोनों समाधान खराब हैं।

सभी उपलब्ध सेवाओं वाले इंटरफेस के रूप में एक सेवा सिंगलटन (IServices) बनाना। उदाहरण: Services.Current.XXXService.Retrieve (), Services.Current.YYYService.Retrieve ()। इस तरह, मेरे पास उन सेवाओं के एक टन के साथ एक विशाल निर्माता नहीं है।

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

ViewModel द्वारा उपयोग की जाने वाली सेवाओं के लिए एक पहलू बनाना और मेरे viewmodel के ctor में इस ऑब्जेक्ट को पास करना। लेकिन फिर, मुझे अपने कॉम्प्लेक्स व्यूमोडल्स में से प्रत्येक के लिए एक मुखौटा बनाना होगा, और यह थोड़ा अधिक हो सकता है ...

यह इतना अधिक एक विरोधी पैटर्न नहीं है, लेकिन यह एक कोड गंध है। अनिवार्य रूप से आप एक पैरामीटर ऑब्जेक्ट बना रहे हैं , लेकिन पीओ रिफैक्टरिंग पैटर्न का बिंदु पैरामीटर सेट से निपटने के लिए है जो अक्सर और बहुत सारे अलग-अलग स्थानों में उपयोग किए जाते हैं , जबकि यह पैरामीटर केवल एक बार उपयोग किया जाएगा। जैसा कि आप उल्लेख करते हैं, यह बिना किसी वास्तविक लाभ के बहुत सारे कोड ब्लोट बनाएगा, और बहुत सारे IoC कंटेनरों के साथ अच्छा नहीं खेलेगा।

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

सोचें कि आप इनमें से किसी एक मॉडल को कैसे परखेंगे। आपका सेटअप कोड कितना बड़ा होने जा रहा है? इसे काम करने के लिए कितनी चीजों को शुरू करने की आवश्यकता है?

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

वास्तव में आपको क्या करने की आवश्यकता है, अपने विचार मॉडल को फिर से तैयार करें ताकि उनकी कम निर्भरता हो । फिर, यदि आपको एक "स्क्रीन" एकत्र करने की आवश्यकता है, तो आप छोटे दृश्य मॉडल को एकत्र करने के लिए एक और दृश्य मॉडल बनाते हैं। यह समग्र दृश्य मॉडल खुद से बहुत अधिक नहीं है, इसलिए यह बदले में समझने और परीक्षण करने में भी काफी आसान है।

यदि आपने इसे ठीक से किया है, तो यह केवल कोड को देखने से स्पष्ट होना चाहिए, क्योंकि आपके पास लघु, संक्षिप्त, विशिष्ट और परीक्षण दृश्य मॉडल होंगे।


बेनाम: हाँ, यह है कि मैं शायद क्या कर खत्म हो जाएगा! महोदय बहुत बहुत धन्यवाद।
अल्फ़ा-अल्फ़ा

खैर, मैंने पहले ही मान लिया कि उसने पहले ही यह कोशिश कर ली है, लेकिन सफल नहीं हुआ। @ अल्फ़ा-अल्फ़ा
युफ़ोरिक

@ युफ़ोरिक: आप इसमें "सफल नहीं" कैसे करते हैं? जैसा कि योदा कहेगा: करो या न करो, कोई कोशिश नहीं है।
Aaronaught

@Aaronaught उदाहरण के लिए उसे वास्तव में सिंगल व्यूमॉडल के सभी डेटा की आवश्यकता है। हो सकता है कि उसके पास ग्रिड हो और अलग-अलग कॉलम अलग-अलग सेवाओं से आए हों। आप रचना के साथ ऐसा नहीं कर सकते।
युफोरिक

@ यूफोरिक: वास्तव में, आप इसे रचना के साथ हल कर सकते हैं , लेकिन यह दृश्य मॉडल स्तर के नीचे किया जा सकता है। यह केवल सही सार बनाने की बात है। उस स्थिति में, आपको आईडी की सूची प्राप्त करने के लिए प्रारंभिक क्वेरी को संभालने के लिए केवल एक सेवा की आवश्यकता होती है, और "रिचर्स" का एक क्रम / सूची / सरणी होती है, जो अपनी जानकारी के साथ एनोटेट करते हैं। ग्रिड को अपना स्वयं का मॉडल बनाएं, और आपने समस्या को प्रभावी रूप से दो निर्भरता के साथ हल किया है, और यह परीक्षण करना बेहद आसान है।
Aaronaught

1

मैं इस बारे में एक पुस्तक लिख सकता हूं ... वास्तव में मैं हूं;)

सबसे पहले, चीजों को करने का कोई सार्वभौमिक "सही" तरीका नहीं है। आपको अन्य कारकों को ध्यान में रखना होगा।

यह संभव है कि आपकी सेवाएँ बहुत अच्छी हो। उन सेवाओं को फेस करने के साथ रैप करना जो इंटरफ़ेस प्रदान करते हैं जो एक विशिष्ट व्यूमॉडल या यहां तक ​​कि संबंधित ViewModels का एक क्लस्टर उपयोग करेगा एक बेहतर समाधान हो सकता है।

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

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


एक बड़े पैमाने पर सेवा अग्रभाग एक संदेश दलाल से बहुत अलग है। यह लगभग निर्भरता स्पेक्ट्रम के विपरीत छोर पर है। इस वास्तुकला की एक बानगी यह है कि भेजने वाले को रिसीवर के बारे में कुछ नहीं पता होता है, और कई रिसीवर (पब / सब या मल्टिकास्ट) हो सकते हैं। शायद आप इसे RPC- शैली "रीमोटिंग" के साथ भ्रमित कर रहे हैं, जो सिर्फ एक दूरस्थ प्रोटोकॉल पर एक पारंपरिक सेवा को उजागर कर रहा है, और प्रेषक अभी भी प्राप्त करने के लिए युग्मित है, दोनों शारीरिक रूप से (समापन बिंदु पता) और तार्किक रूप से (वापसी मान)।
Aaronaught

समानता यह है कि मुखौटा एक राउटर की तरह कार्य करता है, फोन करने वाले को यह नहीं पता होता है कि कौन सी सेवा / सेवाएं कॉल को उसी तरह संभालती है जैसे संदेश भेजने वाले ग्राहक को पता नहीं होता कि कौन संदेश संभालता है।
माइकल ब्राउन

हाँ, लेकिन अग्रभाग तब एक ईश्वर वस्तु है । यह सभी निर्भरताएं हैं जो कि व्यू मॉडल्स के पास हैं, शायद अधिक क्योंकि यह कई लोगों द्वारा साझा की जाने वाली है। वास्तव में आपने ढीले युग्मन के लाभों को समाप्त कर दिया है, जिसके लिए आपने पहले स्थान पर इतनी मेहनत की थी, क्योंकि अब, जब भी कुछ मेगा-फ़ेकडे को छूता है, तो आपके पास कोई सुराग नहीं होता है कि यह वास्तव में किस कार्यक्षमता पर निर्भर करता है। पिक्चर एक क्लास टेस्ट के लिए एक यूनिट टेस्ट लिखता है जो फ़ेसडे का उपयोग करता है। आप अग्रभाग के लिए एक नकली बनाएँ। अब, आप किन तरीकों का मजाक उड़ाते हैं? आपका सेटअप कोड कैसा दिखता है?
Aaronaught

यह एक संदेश ब्रोकर से बहुत अलग है क्योंकि ब्रोकर को संदेश संचालकों के कार्यान्वयन के बारे में कुछ भी नहीं पता है । यह हुड के नीचे IoC का उपयोग करता है। अग्रदूत प्राप्तकर्ता के बारे में सब कुछ जानता है क्योंकि उसे उन्हें कॉल अग्रेषित करना है। बस में शून्य युग्मन है; अग्रभाग में अत्यधिक उच्च युग्मन है। लगभग सब कुछ जो आप बदलते हैं, कहीं भी, साथ ही साथ अग्रभाग को प्रभावित करेगा।
हारून

मुझे लगता है कि भ्रम का हिस्सा यहाँ है - और मैं इसे काफी देखता हूं - बस एक निर्भरता का मतलब है। यदि आपके पास एक वर्ग है जो एक अन्य वर्ग पर निर्भर करता है, लेकिन उस वर्ग के 4 तरीकों को कॉल करता है, तो इसमें 4 निर्भरताएं होती हैं, न कि 1. इसे एक फ़ेकेड के पीछे रखने से निर्भरता की संख्या में परिवर्तन नहीं होता है, यह सिर्फ उन्हें समझने में कठिन बनाता है ।
Aaronaught

0

दोनों का गठबंधन क्यों नहीं?

एक मुखौटा बनाएँ और सभी सेवाओं को अपने viewmodels का उपयोग करें। तब आपके पास खराब एस शब्द के बिना आपके सभी दृश्यम के लिए एकल पहलू हो सकता है।

या आप कंस्ट्रक्टर इंजेक्शन के बजाय संपत्ति इंजेक्शन का उपयोग कर सकते हैं। लेकिन फिर, आपको यह सुनिश्चित करने की आवश्यकता है कि जो ठीक से इंजेक्ट हो रहे हैं।


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