आइए एक कदम पीछे लें और यहां की बड़ी तस्वीर देखें।
IDatabase
जिम्मेदारी क्या है ?
इसके कुछ अलग ऑपरेशन हैं:
- एक कनेक्शन स्ट्रिंग पार्स करें
- एक डेटाबेस (एक बाहरी सिस्टम) के साथ एक कनेक्शन खोलें
- डेटाबेस को संदेश भेजें; संदेश डेटाबेस को स्थिति बदलने के लिए कमांड करता है
- डेटाबेस से प्रतिक्रियाएं प्राप्त करें और उन्हें एक प्रारूप में परिवर्तित करें जिसे कॉलर उपयोग कर सकता है
- कनेक्शन बंद करें
इस सूची को देखकर, आप सोच रहे होंगे, "क्या यह SRP का उल्लंघन नहीं करता है?" लेकिन मुझे नहीं लगता कि यह होता है। सभी ऑपरेशन एक एकल, एकजुट अवधारणा का हिस्सा हैं: डेटाबेस (एक बाहरी सिस्टम) के लिए एक राज्य कनेक्शन का प्रबंधन । यह कनेक्शन स्थापित करता है, यह कनेक्शन की वर्तमान स्थिति पर नज़र रखता है (विशेष रूप से, अन्य कनेक्शन पर किए गए संचालन के संबंध में), यह संकेत देता है कि कनेक्शन की वर्तमान स्थिति के लिए प्रतिबद्ध है, आदि। इस अर्थ में, यह एपीआई के रूप में कार्य करता है। बहुत से कार्यान्वयन विवरणों को छिपाता है, जिनके बारे में अधिकांश कॉल करने वाले परवाह नहीं करेंगे। उदाहरण के लिए, क्या यह HTTP, सॉकेट्स, पाइप्स, कस्टम TCP, HTTPS का उपयोग करता है? कॉलिंग कोड परवाह नहीं करता है; यह केवल संदेश भेजने और प्रतिक्रियाएं प्राप्त करना चाहता है। यह एनकैप्सुलेशन का एक अच्छा उदाहरण है।
क्या हमें यकीन है? क्या हम इनमें से कुछ ऑपरेशन को विभाजित नहीं कर सकते हैं? हो सकता है, लेकिन कोई फायदा न हो। यदि आप उन्हें विभाजित करने का प्रयास करते हैं, तो आपको अभी भी एक केंद्रीय ऑब्जेक्ट की आवश्यकता है जो कनेक्शन को खुला रखता है और / या वर्तमान स्थिति का प्रबंधन करता है। सभी अन्य कार्यों कर रहे हैं दृढ़ता से एक ही राज्य के लिए युग्मित, और यदि आप उन्हें अलग करने की कोशिश, वे तो बस वैसे भी कनेक्शन वस्तु को वापस सौंपने के अंत करने के लिए जा रहे हैं। ये ऑपरेशन स्वाभाविक रूप से और तार्किक रूप से राज्य के लिए युग्मित हैं, और उन्हें अलग करने का कोई तरीका नहीं है। जब हम यह कर सकते हैं, तो Decoupling बहुत अच्छा है, लेकिन इस मामले में, हम वास्तव में नहीं कर सकते। कम से कम डीबी से बात करने के लिए बहुत अलग, स्टेटलेस प्रोटोकॉल के बिना नहीं, और यह वास्तव में एसीआईडी अनुपालन जैसी बहुत महत्वपूर्ण समस्याओं को बहुत कठिन बना देगा। इसके अलावा, कनेक्शन से इन परिचालनों को हटाने की कोशिश करने की प्रक्रिया में, आपको उस प्रोटोकॉल के बारे में विवरण उजागर करने के लिए मजबूर किया जाएगा जो कॉल करने वालों की परवाह नहीं करता है, क्योंकि आपको किसी तरह के "मनमाने" संदेश भेजने के तरीके की आवश्यकता होगी डेटाबेस के लिए।
ध्यान दें कि हम जिस स्टेटफुल प्रोटोकॉल के साथ काम कर रहे हैं, वह आपके अंतिम विकल्प (एक पैरामीटर के रूप में कनेक्शन स्ट्रिंग को पारित करना) को बहुत ठोस रूप से नियमबद्ध करता है।
क्या हमें सेट होने के लिए वास्तव में कनेक्शन स्ट्रिंग की आवश्यकता है?
हाँ। जब तक आपके पास कनेक्शन स्ट्रिंग नहीं है, तब तक आप कनेक्शन नहीं खोल सकते हैं , और जब तक आप कनेक्शन नहीं खोलते हैं , तब तक आप प्रोटोकॉल के साथ कुछ भी नहीं कर सकते हैं। इसलिए एक के बिना एक कनेक्शन ऑब्जेक्ट होना व्यर्थ है।
हम कनेक्शन स्ट्रिंग की आवश्यकता की समस्या को कैसे हल करेंगे?
हम जिस समस्या को हल करने का प्रयास कर रहे हैं, वह यह है कि हम चाहते हैं कि वस्तु हर समय उपयोगी स्थिति में रहे। OO भाषाओं में राज्य का प्रबंधन करने के लिए किस तरह की इकाई का उपयोग किया जाता है? ऑब्जेक्ट्स , इंटरफेस नहीं। इंटरफेस के पास प्रबंधन करने के लिए राज्य नहीं है। क्योंकि आप जिस समस्या को हल करने का प्रयास कर रहे हैं वह राज्य प्रबंधन की समस्या है, एक इंटरफ़ेस वास्तव में यहाँ उपयुक्त नहीं है। एक अमूर्त वर्ग बहुत अधिक प्राकृतिक है। इसलिए एक कंस्ट्रक्टर के साथ एक सार वर्ग का उपयोग करें।
आप वास्तव में कंस्ट्रक्टर के दौरान कनेक्शन खोलने पर भी विचार कर सकते हैं , क्योंकि कनेक्शन खुलने से पहले ही बेकार हो जाता है। protected Open
डेटाबेस को विशिष्ट बनाने के लिए कनेक्शन खोलने की प्रक्रिया के बाद से एक अमूर्त विधि की आवश्यकता होगी । ConnectionString
संपत्ति को केवल इस मामले में पढ़ा जाना अच्छा होगा , क्योंकि कनेक्शन खुला होने के बाद कनेक्शन स्ट्रिंग को बदलना अर्थहीन होगा। (ईमानदारी से, मैं इसे केवल वैसे ही पढ़ूंगा। यदि आप एक अलग स्ट्रिंग के साथ एक कनेक्शन चाहते हैं, तो दूसरी वस्तु बनाएं।)
क्या हमें एक इंटरफ़ेस की आवश्यकता है?
एक इंटरफ़ेस जो उपलब्ध संदेशों को निर्दिष्ट करता है जो आप कनेक्शन पर भेज सकते हैं और प्रतिक्रिया के प्रकार जो आप प्राप्त कर सकते हैं वह उपयोगी हो सकता है। यह हमें उन कोडों को लिखने की अनुमति देगा जो इन परिचालनों को निष्पादित करते हैं लेकिन कनेक्शन खोलने के तर्क के लिए युग्मित नहीं होते हैं। लेकिन वह बिंदु है: कनेक्शन का प्रबंधन इंटरफ़ेस के भाग का हिस्सा नहीं है, "मैं क्या संदेश भेज सकता हूं और डेटाबेस से / के लिए मुझे कौन से संदेश वापस मिल सकते हैं?", इसलिए कनेक्शन स्ट्रिंग भी उसका हिस्सा नहीं होना चाहिए इंटरफेस।
यदि हम इस मार्ग पर जाते हैं, तो हमारा कोड कुछ इस तरह दिखाई दे सकता है:
interface IDatabase {
void ExecuteNoQuery(string sql);
void ExecuteNoQuery(string[] sql);
//Various other methods all requiring ConnectionString to be set
}
abstract class ConnectionStringDatabase : IDatabase {
public string ConnectionString { get; }
public Database(string connectionString) {
this.ConnectionString = connectionString;
this.Open();
}
protected abstract void Open();
public abstract void ExecuteNoQuery(string sql);
public abstract void ExecuteNoQuery(string[] sql);
//Various other methods all requiring ConnectionString to be set
}