विजिटर पैटर्न को समझना


16

मेरे पास कक्षाओं का एक पदानुक्रम है जो GUI नियंत्रणों का प्रतिनिधित्व करता है। कुछ इस तरह:

Control->ContainerControl->Form

मुझे अलग-अलग सामानों के साथ काम करने वाले अल्गोरिटम्स की एक श्रृंखला को लागू करना होगा और मैं सोच रहा हूं कि विज़िटर पैटर्न सबसे साफ समाधान होगा। उदाहरण के लिए एक एल्गोरिथ्म लें जो वस्तुओं के पदानुक्रम का Xml प्रतिनिधित्व बनाता है। 'क्लासिक' दृष्टिकोण का उपयोग करके मैं यह करूँगा:

public abstract class Control
{
    public virtual XmlElement ToXML(XmlDocument document)
    {
        XmlElement xml = document.CreateElement(this.GetType().Name);
        // Create element, fill it with attributes declared with control
        return xml;
    }
}

public abstract class ContainerControl : Control
{
    public override XmlElement ToXML(XmlDocument document)
    {
        XmlElement xml = base.ToXML(document);
        // Use forech to fill XmlElement with child XmlElements
        return xml;
    }
}

public class Form : ContainerControl
{
    public override XmlElement ToXML(XmlDocument document)
    {
        XmlElement xml = base.ToXML(document);
        // Fill remaining elements declared in Form class
        return xml;
    }
}

लेकिन मुझे यकीन नहीं है कि विज़िटर पैटर्न के साथ ऐसा कैसे किया जाए। यह मूल कार्यान्वयन है:

public class ToXmlVisitor : IVisitor
{
    public void Visit(Form form)
    {
    }
}

चूंकि अमूर्त वर्ग भी कार्यान्वयन में मदद करता है, मुझे यकीन नहीं है कि टॉक्सिमविसिटर में ठीक से कैसे करें?

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


आपका प्रश्न क्या है?
gnat

मूल रूप से ToXml () विधि को विज़िटर पैटर्न का उपयोग करके कैसे फिर से लिखना है।
नेजरेली


लिंक के लिए धन्यवाद। डायनेमिक प्रेषण पारंपरिक विज़िटर पैटर्न को सरल करता है लेकिन यह बहुत अधिक नहीं बदलता है।
नेज़रेली

@Nezreli हाँ यह करता है। यह उन कक्षाओं के साथ काम करता है जो विज़िटर पैटर्न का समर्थन नहीं करते हैं, जैसे कि विंडोज फॉर्म आपके द्वारा नियंत्रित कर रहे हैं।
क्रिश वंडरमोटेन

जवाबों:


17

विज़िटर पैटर्न प्रोग्रामिंग भाषाओं में दोहरी बाइंडिंग का अनुकरण करने वाला एक तंत्र है जो केवल एकल बाइंडिंग का समर्थन करता है। दुर्भाग्य से, यह कथन बहुत कुछ स्पष्ट नहीं कर सकता है, इसलिए मुझे एक सरल उदाहरण के साथ समझाएं।

.NET और C # में, आप जिस प्लेटफ़ॉर्म का उपयोग कर रहे हैं, ऑब्जेक्ट ToString()फ़ंक्शन का उपयोग करके स्ट्रिंग में परिवर्तित किया जा सकता है । वह फ़नटेशन क्या करता है, यानी कोड निष्पादित किया जा रहा है, उस वस्तु के प्रकार पर निर्भर करता है जिसे आप इसे लागू कर रहे हैं (यह एक आभासी तरीका है)। किस कोड को निष्पादित किया जाता है यह एक बात, एक प्रकार की वस्तु पर निर्भर करता है, इसलिए उपयोग किए जाने वाले तंत्र को एकल बंधन कहा जाता है।

लेकिन क्या होगा अगर मैं किसी वस्तु को स्ट्रिंग में बदलने के लिए एक से अधिक तरीके चाहता हूं, प्रत्येक अलग तरह की वस्तु के लिए? क्या होगा यदि मैं वस्तुओं को तार में बदलने के लिए दो तरीके चाहता हूं, ताकि निष्पादित किया जा रहा कोड दो चीजों पर निर्भर करता है: न केवल परिवर्तित होने वाली वस्तु, बल्कि जिस तरह से हम इसे परिवर्तित करना चाहते हैं?

यदि हम दोहरी बाध्यकारी थे तो इसे अच्छी तरह से हल किया जा सकता है। लेकिन C # सहित अधिकांश OO भाषाएँ केवल एकल बाइंडिंग का समर्थन करती हैं।

विज़िटर पैटर्न समस्या को हल करता है, दोहरे बंधन को दो सक्सेसिव सिंगल बाइंडिंग में बदलकर।

ऊपर हमारे उदाहरण में, यह रूपांतरित करने के लिए एक आभासी विधि का उपयोग करेगा, जो रूपांतरण एल्गोरिथ्म को लागू करने वाली वस्तु में दूसरी आभासी विधि कहता है।

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

आप .NET के विंडोज फॉर्म क्लास का उपयोग करने लगते हैं, जिसमें विज़िटर पैटर्न का समर्थन नहीं है। विशेष रूप से, उन्हें एक public virtual void Accept(IVisitor)विधि की आवश्यकता होगी , जो स्पष्ट रूप से उनके पास नहीं है।

तो, विकल्प क्या है? खैर, .NET न केवल सिंगल बाइंडिंग का समर्थन करता है, यह डायनेमिक बाइंडिंग को भी सपोर्ट करता है, जो कि ड्युअल बाइंडिंग की तुलना में अधिक शक्तिशाली है।

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

अपडेट करें:

तकनीक को अपनी विशिष्ट समस्या पर लागू करने के लिए, पहले अपनी विस्तार विधि को परिभाषित करें:

public static XmlDocument ToXml(this Control control)
{
    XmlDocument xml = new XmlDocument();
    XmlElement root = xml.CreateElement(control.GetType().Name);
    xml.AppendChild(root);

    Visit(control, xml, root);

    return xml;
}

डायनेमिक डिस्पैचर बनाएं:

private static void Visit(Control control, XmlDocument xml, XmlElement root)
{
    dynamic dynamicControl = control; //notice the 'dynamic' type.
                                      //this is the key to dynamic dispatch

    VisitCore(dynamicControl, xml, root);
}

फिर विशिष्ट तरीकों को भरें:

private static void VisitCore(Control control, XmlDocument xml, XmlElement root)
{
    // TODO: specific Control handling
}

private static void VisitCore(ContainerControl control, XmlDocument xml, XmlElement root)
{
    // call the "base" method
    VisitCore(control as Control, xml, root);

    // TODO: specific ContainerControl handling
    // for example:
    foreach (Control child in control.Controls)
    {
        XmlElement element = xml.CreateElement(child.GetType().Name);
        root.AppendChild(element);

        // call the dynamic dispatcher method
        Visit(child, xml, element);
    }
}

private static void VisitCore(Form control, XmlDocument xml, XmlElement root)
{
    // call the "base" method
    VisitCore(control as ContainerControl, xml, root);

    // TODO: specific Form handling
}

.NET में डायनामिक डिस्पैच वास्तव में काफी शक्तिशाली है .. हालाँकि मैंने देखा कि यह थोड़ा सा हो सकता है ... अच्छी तरह से .. धीमा, लेकिन यह कोड की एक ही लाइन में होता है जो कई वर्गों में
सेवरल

फिर भी, डायनामिक डिस्पैच मेरी समस्या का समाधान नहीं करेगा क्योंकि मेरे टॉक्सिल एल्गोरिथ्म के लिए मुझे विरासत श्रृंखला के सभी प्रकारों को 'विज़िट' करना होगा। मेरे उदाहरण में इसे एक सफल XML रूपांतरण करने के लिए नियंत्रण, कन्टेन्टरकंट्रोल और फॉर्म पर जाने की आवश्यकता है।
नेज़रेली

@Nezreli यह आपकी समस्या को हल कर सकता है, मैंने आपको कैसे दिखाने के लिए अपना जवाब अपडेट किया है।
क्रिश वंडरमोटेन

मैंने डायनेमिक चर परिभाषा में एक टिप्पणी जोड़ने की अनुमति ली। इससे पहले कि मैंने इसे देखा, मुझे कोड की दो रीड्स लगीं, और यह पूरी कहानी की कुंजी है।
क्रिस्टी डियाकोन्सकु
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.