मॉडल-व्यू-प्रस्तुतकर्ता कार्यान्वयन विचार


34

मैं एक UI और मॉडल के बीच अच्छे डिकम्प्लिंग को कैसे लागू करूं, इसका एक अच्छा समझ प्राप्त करने की कोशिश कर रहा हूं, लेकिन मुझे यह पता लगाने में परेशानी हो रही है कि लाइनों को कहां विभाजित करना है।

मैं मॉडल-व्यू-प्रस्तोता देख रहा हूं, लेकिन मुझे यकीन नहीं है कि इसे कैसे लागू किया जाए। उदाहरण के लिए, मेरे विचार में कई संवाद हैं।

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

मैं कोशिश कर रहा हूँ:

  1. इसे जितना संभव हो उतना कम करें
  2. आदर्श रूप से प्रस्तुतकर्ता / मॉडल को अन्य भाषाओं के दृश्यों के साथ युगल करना संभव है (मैंने एक टन अंतर-भाषा सामान नहीं किया है, लेकिन मुझे पता है कि यह संभव है, विशेष रूप से जितना void(void)मैं छड़ी कर सकता हूं, कम से कम एक सी # ऐप के साथ C ++ लाइब्रेरी ...
  3. कोड को साफ और सरल रखें

तो .. कोई सुझाव कैसे बातचीत को संभाला जाना चाहिए?


क्या आपने इस लेख को देखा है ?: en.wikipedia.org/wiki/Model-view-presenter
Bernard

1
मेरे पास है .. मुझे यह थोड़ा जल्दी और उच्च स्तर पर मिला, मैं बेहतर तरीके से समझना चाहता हूं कि कैसे एक बड़ी परियोजना में कई संवादों को संभालना है जितना संभव हो उतना कम युग्मन के साथ ..
trycatch

जवाबों:


37

एक फिसलन ढलान पर आपका स्वागत है। आप इस बिंदु से महसूस करते हैं कि सभी मॉडल-व्यू इंटरैक्शन का एक अंतहीन भिन्नता है। एमवीसी, एमवीपी (टैलिगेंट, डॉल्फिन, पैसिव व्यू), एमवीवीएम सिर्फ कुछ के नाम के लिए।

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

इसे करने के कई तरीके हैं। प्रत्येक संवाद / रूप को एक अलग दृष्टिकोण के रूप में मानकर इस संभाले को देखना बहुत आम है। कई बार विचारों और प्रस्तुतकर्ताओं के बीच 1: 1 संबंध होता है। यह एक कठिन, तेज नियम नहीं है। एक प्रस्तुतकर्ता के पास कई संबंधित विचारों या इसके विपरीत को संभालने के लिए यह काफी सामान्य है। यह सब दृश्य की जटिलता और व्यावसायिक तर्क की जटिलता पर निर्भर करता है।

जैसा कि विचार और प्रस्तुतकर्ता एक-दूसरे के संदर्भ प्राप्त करते हैं, इसे कभी-कभी वायरिंग भी कहा जाता है । आपके पास तीन विकल्प हैं:

प्रस्तुतकर्ता
एक फ़ॉर्म प्रस्तुत करता है या संवाद दृश्य को लागू करता है। प्रपत्र में ईवेंट हैंडलर होते हैं जो प्रत्यक्ष फ़ंक्शन कॉल का उपयोग करके प्रस्तुतकर्ता को वितरित करते हैं:

MyForm.SomeEvent(Sender)
{
  Presenter.DoSomething(Sender.Data);
}

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

प्रस्तुतकर्ता देखने के लिए एक संदर्भ रखता है
परिदृश्य में दृश्य उपयोगकर्ता को प्रदर्शित होने वाले डेटा के लिए गुणों को उजागर करता है। प्रस्तुतकर्ता घटनाओं के लिए सुनता है और दृश्य पर गुणों में हेरफेर करता है:

Presenter.SomeEvent(Sender)
{
  DomainObject.DoSomething(View.SomeProperty);
  View.SomeOtherProperty = DomainObject.SomeData;
}

दोनों एक दूसरे पर एक परिपत्र निर्भरता बनाने का संदर्भ देते हैं।
यह परिदृश्य वास्तव में दूसरों की तुलना में काम करना आसान है। प्रस्तुतकर्ता में विधियों को कॉल करके दृश्य घटनाओं पर प्रतिक्रिया करता है। प्रस्तुतकर्ता उजागर गुणों के माध्यम से दृश्य से डेटा को पढ़ता / संशोधित करता है।

View.SomeEvent(Sender)
{
  Presenter.DoSomething();
}

Presenter.DoSomething()
{
  View.SomeProperty = DomainObject.Calc(View.SomeProperty);
}

एमवीपी पैटर्न के साथ विचार करने के लिए अन्य मुद्दे हैं। निर्माण क्रम, वस्तु जीवनकाल, जहां वायरिंग होती है, एमवीपी ट्रायड्स के बीच संचार होता है, लेकिन यह उत्तर पहले से ही काफी लंबा हो गया है।


1
यह निश्चित रूप से सहायक है। त्रैमासिक और जीवनकाल के बीच संचार वह जगह है जहां मुझे वर्तमान में परेशानी हो रही है कि मैं इसमें से कुछ को समझ रहा हूं।
trycatch

8

जैसा कि सभी ने कहा है, दर्जनों राय हैं और उनमें से एक भी सही या गलत नहीं है। पैटर्न के असंख्य में उतरे बिना और केवल एमवीपी पर ध्यान केंद्रित करने के लिए यहां कुछ कार्यान्वयन के सुझाव दिए गए हैं।

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

यहाँ एक उदाहरण है। पहले हमारे पास उपयोगकर्ता के लिए एक संदेश प्रदर्शित करने के लिए एक सरल विधि के साथ एक दृश्य वर्ग है:

interface IView
{
  public void InformUser(string message);
}

अब यहाँ प्रस्तुतकर्ता है। ध्यान दें कि प्रस्तोता अपने निर्माता में एक आईवीईवाई लेता है।

class Presenter
{
  private IView _view;
  public Presenter(IView view)
  {
    _view = view;
  }
}

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

class View : IView
{
  private Presenter _presenter;

  public View()
  {
    _presenter = new Presenter(this);
  }

  public void InformUser(string message)
  {
    MessageBox.Show(message);
  }
}

प्रस्तुतकर्ता इस बात की परवाह नहीं करता है कि दृश्य उस विधि को कैसे लागू करता है जो वह करता है। सभी प्रस्तुतकर्ता के लिए पता है, यह एक लॉग फ़ाइल को लिख सकता है और उपयोगकर्ता को भी नहीं दिखा सकता है।

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

class Presenter
{
  public void DoSomething()
  {
    _view.InformUser("Starting model processing...");
  }
}

यह वह जगह है जहाँ आप अपना डिकॉयलिंग प्राप्त करते हैं। प्रस्तुतकर्ता केवल IVIV के कार्यान्वयन के लिए एक संदर्भ रखता है और वास्तव में परवाह नहीं करता है कि यह कैसे लागू किया जाता है।

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


4

मुझे लगता है कि यह याद रखना महत्वपूर्ण है कि नियंत्रक / प्रस्तुतकर्ता वह जगह है जहां कार्रवाई वास्तव में होती है। आवश्यकता के कारण नियंत्रक में युग्मन अपरिहार्य है।

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

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

यह कहा जा रहा है, आपको यह सब काम करने के लिए विभिन्न घटकों के बीच संदर्भ रखना होगा। डेटा को पुश करने के लिए कंट्रोलर को व्यू के बारे में जानने की आवश्यकता है, व्यू को यह बताने के लिए कंट्रोलर के बारे में जानने की जरूरत है कि कब बदलाव हुआ है (जैसे कि यूजर कब "सेव" या "न्यू ..." पर क्लिक करता है)। नियंत्रक को डेटा खींचने के लिए मॉडल के बारे में जानने की आवश्यकता है, लेकिन मेरा तर्क है कि मॉडल को किसी और चीज के बारे में नहीं जानना चाहिए।

कैविएट: मैं एक पूरी तरह से मैक, ऑब्जेक्टिव-सी, कोको बैकग्राउंड से आता हूं जो वास्तव में आपको एमवीसी प्रतिमान में धकेल देता है कि आप चाहते हैं या नहीं।


यह निश्चित रूप से मेरा लक्ष्य है। मेरी मुख्य समस्या यह है कि व्यू को कैसे सेट किया जाए - चाहे वह प्रत्येक संवाद के उदाहरण के साथ एक वर्ग होना चाहिए, और फिर View.Getters का उपयोग करें जो Dialog.Getters को कॉल करता है, या यदि प्रस्तुतकर्ता को सीधे डायलॉग कॉल करने में सक्षम होना चाहिए। इस बहुत कसकर युग्मित लगता है, इसलिए शायद नहीं)?
trycatch

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

2
मैं निश्चित रूप से सहमत हूं कि पी / सी व्यू के लिए ज़िम्मेदार होना चाहिए, लेकिन मैंने सोचा कि एमवीपी को शक्तिशाली बनाने के लिए क्या करना चाहिए, पूरे यूआई लाइब्रेरी को बाहर खींचने और एक नए प्लग को प्लग करने की क्षमता थी और कुछ मालिश के साथ (dllimporting और whatnot) यह जगह में एक और एक चलाने में सक्षम हो। क्या यह नियंत्रक / प्रस्तुतकर्ता के साथ संवादों को सीधे एक्सेस करने में अधिक कठिन नहीं होगा? मैं निश्चित रूप से सिर्फ यह भी समझता लोगों का तर्क है की कोशिश नहीं कर रहा हूँ, :)
trycatch

मुझे लगता है कि वास्तविक शक्ति दो दिशाओं से आती है: पहला यह कि व्यू और मॉडल का अन्य से कोई लेना-देना नहीं है, और दूसरा यह कि अधिकांश विकास कार्य, ऐप का इंजन, बड़े करीने से किया जाता है इकाई, नियंत्रक। लेकिन जिम्मेदारी का कुछ खून बह रहा है। कम से कम इंटरफेसों की अदला-बदली कंट्रोलर में की जाएगी और व्यू से कोई भी लिंक न्यूनतम होगा। जैसा कि दूसरों ने कहा है, तर्क के कुछ रक्तस्राव की उम्मीद है और अनुमति दी गई है। MVC एक जादू की गोली नहीं है।
फिलिप रेगन

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

2

सामान्य तौर पर, आप चाहते हैं कि आपका मॉडल उस मॉडल के साथ सभी इंटरैक्शन को इनकैप्सुलेट करे। उदाहरण के लिए, आपके CRUD कार्य (क्रिएट, रीड, अपडेट, डिलीट) सभी मॉडल का हिस्सा हैं। वही विशेष गणना के लिए जाता है। इसके लिए कुछ अच्छे कारण हैं:

  • इस कोड के लिए अपने परीक्षण को स्वचालित करना आसान है
  • यह सभी महत्वपूर्ण सामान को एक स्थान पर रखता है

आपके नियंत्रक (एमवीसी ऐप) में, आप जो भी मॉडल कर रहे हैं, वह आपके विचार में उपयोग करने के लिए आवश्यक मॉडल एकत्र कर रहा है, और मॉडल पर उपयुक्त फ़ंक्शन को कॉल कर रहा है। मॉडल की स्थिति में कोई भी परिवर्तन इस परत में होता है।

आपका दृश्य आपके द्वारा तैयार किए गए मॉडल को प्रदर्शित करता है। अनिवार्य रूप से, दृश्य केवल मॉडल को पढ़ता है और तदनुसार अपने आउटपुट को समायोजित करता है।

सामान्य सिद्धांत को वास्तविक कक्षाओं में मैप करना

याद रखें कि आपके संवाद दृश्य हैं। यदि आपके पास पहले से ही डायलॉग क्लास है, तो दूसरा "व्यू" क्लास बनाने का कोई कारण नहीं है। प्रस्तुतकर्ता परत आवश्यक रूप से दृश्य में नियंत्रण के लिए मॉडल को बांधता है। व्यापार तर्क और सभी महत्वपूर्ण डेटा मॉडल में संग्रहीत हैं।

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