MongoDB
 sql >> डेटाबेस >  >> NoSQL >> MongoDB

डेटा एक्सेस लेयर के लिए डिज़ाइन पैटर्न

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

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

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

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

public interface GreatDAO {
    User getUser(int id);
    void saveUser(User u);
}
public class TheGreatestDAO implements GreatDAO {
   protected TheGeatestDAO(){}
   ... 
}
public class GreatDAOFactory {
     private static GreatDAO dao = null;
     protected static synchronized GreatDao setDAO(GreatDAO d) {
         GreatDAO old = dao;
         dao = d;
         return old;
     }
     public static synchronized GreatDAO getDAO() {
         return dao == null ? dao = new TheGreatestDAO() : dao;
     }
}

public class App {
     void setUserName(int id, String name) {
          GreatDAO dao =  GreatDAOFactory.getDao();
          User u = dao.getUser(id);
          u.setName(name);
          dao.saveUser(u);
     }
}

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

इस दृष्टिकोण के साथ, आपको केवल GreatDAOFactory.getDAO() को बदलना है। और इसे एक अलग वर्ग का उदाहरण बनाएं, और आपका सभी एप्लिकेशन कोड बिना किसी बदलाव के नए डेटाबेस का उपयोग करेगा।

वास्तविक जीवन में, यह अक्सर कोड में किसी भी बदलाव के बिना किया जाता है:फ़ैक्टरी विधि को संपत्ति सेटिंग के माध्यम से कार्यान्वयन वर्ग का नाम मिलता है, और प्रतिबिंब का उपयोग करके इसे तुरंत चालू करता है, इसलिए, कार्यान्वयन को स्विच करने के लिए आपको केवल एक संपत्ति संपादित करने की आवश्यकता है फ़ाइल। वास्तव में ढांचे हैं - जैसे spring या guice - जो आपके लिए इस "निर्भरता इंजेक्शन" तंत्र का प्रबंधन करता है, लेकिन मैं विवरण में नहीं जाऊंगा, पहले, क्योंकि यह वास्तव में आपके प्रश्न के दायरे से बाहर है, और इसलिए भी, क्योंकि मुझे जरूरी नहीं है कि आपको इसका उपयोग करने से लाभ मिलता है वे ढांचे अधिकांश अनुप्रयोगों के लिए उनके साथ एकीकृत करने में परेशानी के लायक हैं।

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

ऐसा करने के लिए, आपको एक परीक्षण ढांचा चाहिए, जैसे Mockito , जो आपको किसी ऑब्जेक्ट या विधि की कार्यक्षमता को "मॉक आउट" करने की अनुमति देता है, इसे "डमी" ऑब्जेक्ट के साथ पूर्वनिर्धारित व्यवहार के साथ बदल देता है (मैं विवरण छोड़ दूंगा, क्योंकि, यह फिर से दायरे से बाहर है)। तो, आप अपने DAO की जगह यह डमी ऑब्जेक्ट बना सकते हैं, और GreatDAOFactory बना सकते हैं GreatDAOFactory.setDAO(dao) पर कॉल करके असली चीज़ के बजाय अपना डमी लौटाएं परीक्षण से पहले (और बाद में इसे बहाल करना)। यदि आप इंस्टेंस क्लास के बजाय स्थिर विधियों का उपयोग कर रहे थे, तो यह संभव नहीं होगा।

एक और लाभ, जो ऊपर वर्णित डेटाबेस को स्विच करने के समान है, अतिरिक्त कार्यक्षमता के साथ आपके दाओ को "पिंपिंग अप" कर रहा है। मान लीजिए कि डेटाबेस में डेटा की मात्रा बढ़ने पर आपका एप्लिकेशन धीमा हो जाता है, और आप तय करते हैं कि आपको कैशे लेयर की आवश्यकता है। एक रैपर वर्ग को लागू करें, जो डेटाबेस तक पहुँचने के लिए वास्तविक दाओ उदाहरण (इसे एक कंस्ट्रक्टर परम के रूप में प्रदान किया गया) का उपयोग करता है, और मेमोरी में पढ़ी गई वस्तुओं को कैश करता है, ताकि उन्हें तेजी से वापस किया जा सके। फिर आप अपना GreatDAOFactory.getDAO . बना सकते हैं आवेदन के लिए इसका लाभ उठाने के लिए, इस रैपर को तुरंत चालू करें।

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

एक समान रूप से व्यापक रूप से उपयोग किया जाता है (लेकिन, मेरी राय में, निम्न) "कारखाना" विधि का विकल्प dao बना रहा है सभी वर्गों में एक सदस्य चर जिसे इसकी आवश्यकता है:

public class App {
   GreatDao dao;
   public App(GreatDao d) { dao = d; }
}

इस तरह, इन वर्गों को इंस्टेंट करने वाले कोड को डाओ ऑब्जेक्ट (अभी भी फ़ैक्टरी का उपयोग कर सकता है) को इंस्टेंट करने की आवश्यकता है, और इसे एक कंस्ट्रक्टर पैरामीटर के रूप में प्रदान करें। ऊपर वर्णित निर्भरता इंजेक्शन ढांचे, आमतौर पर ऐसा ही कुछ करते हैं।

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




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. एंबेडेड मोंगोडीबी दस्तावेज़ को सी # ड्राइवर के साथ सहेजने पर आईडी नहीं मिल रही है

  2. एमजीओ एकत्रीकरण:क्वेरी और अनमर्शल मिश्रित परिणामों के लिए मॉडल प्रकारों का पुन:उपयोग कैसे करें?

  3. MongoDB सरणी में मानों को स्वैप करें

  4. Android और MongoDB पर SQLite सिंक्रनाइज़ेशन के साथ

  5. पारित तर्क 24 हेक्स वर्णों की एक स्ट्रिंग होना चाहिए - मुझे लगता है कि यह है