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


15

समस्या

मान लीजिए कि मेरे पास एक वर्ग है DataSourceजो एक ReadDataविधि प्रदान करता है (और शायद दूसरों को, लेकिन चलो चीजों को सरल रखें) एक .mdbफ़ाइल से डेटा पढ़ने के लिए :

var source = new DataSource("myFile.mdb");
var data = source.ReadData();

कुछ साल बाद, मैं तय करता हूं कि मैं डेटा स्रोतों के रूप .xmlमें फाइलों के अलावा फाइलों का समर्थन करने में सक्षम होना चाहता हूं .mdb। "डेटा पढ़ने" के लिए कार्यान्वयन फ़ाइलों .xmlऔर .mdbफ़ाइलों के लिए काफी भिन्न है ; इस प्रकार, अगर मुझे सिस्टम को खरोंच से डिजाइन करना था, तो मैं इसे इस तरह परिभाषित करूंगा:

abstract class DataSource {
    abstract Data ReadData();
    static DataSource OpenDataSource(string fileName) {
        // return MdbDataSource or XmlDataSource, as appropriate
    }
}

class MdbDataSource : DataSource {
    override Data ReadData() { /* implementation 1 */ }
}

class XmlDataSource : DataSource {
    override Data ReadData() { /* implementation 2 */ }
}

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

var source = new DataSource("myFile.mdb");

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


समाधान

ये ऐसे उपाय हैं जिनसे मैं उभर सकता हूं:

  1. DataSource कंस्ट्रक्टर को एक उपप्रकार ( MdbDataSourceया XmlDataSource) वापस करें। यह मेरी सभी समस्याओं को हल करेगा। दुर्भाग्य से, C # इसका समर्थन नहीं करता है।

  2. विभिन्न नामों का उपयोग करें:

    abstract class DataSourceBase { ... }    // corresponds to DataSource in the example above
    
    class DataSource : DataSourceBase {      // corresponds to MdbDataSource in the example above
        [Obsolete("New code should use DataSourceBase.OpenDataSource instead")]
        DataSource(string fileName) { ... }
        ...
    }
    
    class XmlDataSource : DataSourceBase { ... }

    यही कारण है कि मैंने इसका उपयोग किया क्योंकि यह कोड को पीछे से संगत (यानी new DataSource("myFile.mdb")अभी भी काम करने के लिए कॉल ) रखता है । दोष: नाम उतने वर्णनात्मक नहीं हैं जितने होने चाहिए।

  3. DataSourceवास्तविक कार्यान्वयन के लिए एक "आवरण" बनाएं :

    class DataSource {
        private DataSourceImpl impl;
    
        DataSource(string fileName) {
            impl = ... ? new MdbDataSourceImpl(fileName) : new XmlDataSourceImpl(fileName);
        }
    
        Data ReadData() {
            return impl.ReadData();
        }
    
        abstract private class DataSourceImpl { ... }
        private class MdbDataSourceImpl : DataSourceImpl { ... }
        private class XmlDataSourceImpl : DataSourceImpl { ... }
    }

    दोष: प्रत्येक डेटा स्रोत विधि (जैसे ReadData) बॉयलरप्लेट कोड द्वारा रूट की जानी चाहिए। मुझे बॉयलरप्लेट कोड पसंद नहीं है। यह बेमानी है और कोड को काटता है।

क्या कोई ऐसा सुरुचिपूर्ण समाधान है जिसे मैंने याद किया है?


5
क्या आप अपने मुद्दे को # 3 के साथ थोड़ा और विस्तार से बता सकते हैं? यह मेरे लिए सुरुचिपूर्ण लगता है। (या पीछे की ओर अनुकूलता बनाए रखते हुए आप जितने सुंदर हैं।)
पीडीआर

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

@pdr: 1. मेथड सिग्नेचर में हर बदलाव एक जगह पर करना पड़ता है। 2. मैं या तो Impl वर्गों को आंतरिक और निजी बना सकता हूं, जो असुविधाजनक है यदि कोई ग्राहक केवल Xml डेटा स्रोत में उपलब्ध विशिष्ट कार्यक्षमता तक पहुंचना चाहता है। या मैं उन्हें सार्वजनिक कर सकता हूं, जिसका अर्थ है कि ग्राहकों के पास अब एक ही काम करने के दो अलग-अलग तरीके हैं।
हेनजी

2
@ हिनजी: मैं विकल्प 3 पसंद करता हूं। यह मानक "मुखौटा" पैटर्न है। आपको यह जांचना चाहिए कि क्या आपको वास्तव में कार्यान्वयन के लिए हर डेटा स्रोत विधि को सौंपना है, या बस कुछ। शायद अभी भी कुछ सामान्य कोड हैं जो "डेटा स्रोत" में रहता है?
डॉक ब्राउन

यह शर्म की बात है कि newक्लास ऑब्जेक्ट का एक तरीका नहीं है (ताकि आप खुद क्लास को उप-वर्ग कर सकें - एक ऐसी तकनीक जिसे मेटाक्लासेस के रूप में जाना जाता है - और newवास्तव में जो करता है उसे नियंत्रित करता है) लेकिन यह सी # (या जावा, या सी ++) कैसे काम करता है।
डोनाल्ड फेलो

जवाबों:


12

मैं आपके दूसरे विकल्प के वेरिएंट के लिए जाऊंगा जो आपको पुराने, बहुत सामान्य, नाम को चरणबद्ध करने की अनुमति देता है DataSource:

abstract class AbstractDataSource { ... } // corresponds to the abstract DataSource in the ideal solution

class XmlDataSource : AbstractDataSource { ... }
class MdbDataSource : AbstractDataSource { ... } // contains all the code of the existing DataSource class

[Obsolete("New code should use AbstractDataSource instead")]
class DataSource : MdbDataSource { // an 'empty shell' to keep old code working.
    DataSource(string fileName) { ... }
}

यहां एकमात्र दोष यह है कि नए बेस-क्लास में सबसे स्पष्ट नाम नहीं हो सकता है, क्योंकि मूल वर्ग के लिए उस नाम का पहले ही दावा किया गया था और पीछे की संगतता के लिए उस तरह बने रहने की आवश्यकता है। अन्य सभी वर्गों के अपने वर्णनात्मक नाम हैं।


1
जब मैं प्रश्न पढ़ता हूँ तो मेरे दिमाग में यही बात आती है। हालांकि मुझे ओपी का विकल्प 3 अधिक पसंद है।
डॉक ब्राउन

यदि सभी नए कोड को नए नामस्थान में रखा जाए तो बेस क्लास सबसे स्पष्ट नाम हो सकता है। लेकिन मुझे यकीन नहीं है कि यह एक अच्छा विचार है।
15

आधार वर्ग का प्रत्यय "आधार" होना चाहिए। कक्षा DataSourceBase
स्टीफन

6

सबसे अच्छा समाधान आपके विकल्प # 3 के करीब होगा। DataSourceअधिकतर अब जैसा है, वैसा ही रखें और सिर्फ पाठक के हिस्से को अपनी कक्षा में निकालें।

class DataSource {
    private Reader reader;

    DataSource(string fileName) {
        reader = ... ? new MdbReader(fileName) : new XmlReader(fileName);
    }

    Data ReadData() {
        return reader.next();
    }

    abstract private class Reader { ... }
    private class MdbReader : Reader { ... }
    private class XmlReader : Reader { ... }
}

इस तरह, आप डुप्लिकेट कोड से बचते हैं, और आगे के एक्सटेंशन के लिए खुले रहते हैं।


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