समस्या
मान लीजिए कि मेरे पास एक वर्ग है 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");
पुस्तकालय का उपयोग कर विभिन्न ग्राहकों में। धिक्कार है मुझे, मैं पहली जगह में एक कारखाना विधि का उपयोग क्यों नहीं किया?
समाधान
ये ऐसे उपाय हैं जिनसे मैं उभर सकता हूं:
DataSource कंस्ट्रक्टर को एक उपप्रकार (
MdbDataSource
याXmlDataSource
) वापस करें। यह मेरी सभी समस्याओं को हल करेगा। दुर्भाग्य से, C # इसका समर्थन नहीं करता है।विभिन्न नामों का उपयोग करें:
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")
अभी भी काम करने के लिए कॉल ) रखता है । दोष: नाम उतने वर्णनात्मक नहीं हैं जितने होने चाहिए।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
) बॉयलरप्लेट कोड द्वारा रूट की जानी चाहिए। मुझे बॉयलरप्लेट कोड पसंद नहीं है। यह बेमानी है और कोड को काटता है।
क्या कोई ऐसा सुरुचिपूर्ण समाधान है जिसे मैंने याद किया है?
new
क्लास ऑब्जेक्ट का एक तरीका नहीं है (ताकि आप खुद क्लास को उप-वर्ग कर सकें - एक ऐसी तकनीक जिसे मेटाक्लासेस के रूप में जाना जाता है - और new
वास्तव में जो करता है उसे नियंत्रित करता है) लेकिन यह सी # (या जावा, या सी ++) कैसे काम करता है।