android - सामग्री प्रदाता रिपोजिटरी पैटर्न का कार्यान्वयन है?




design-patterns android-mvp (6)

रिपोजिटरी पैटर्न को हेएट और रॉब मी द्वारा डिज़ाइन पैटर्न के रूप में परिभाषित किया गया है जो डोमेन ऑब्जेक्ट्स तक पहुंचने के लिए संग्रह-जैसे इंटरफ़ेस का उपयोग करके डोमेन और डेटा मैपिंग परतों के बीच मध्यस्थता करता है

असल में यह एक या अधिक I / O डिवाइस (क्लाउड, डिस्क, डेटा बेस इत्यादि) को एक सामान्य संग्रह-जैसे इंटरफ़ेस में सार तत्वित करता है जहां आप डेटा को पढ़, लिखना, ढूंढना और हटाना चाहते हैं

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

हालांकि, जैसा कि कोर्सरा कोर्स में प्रोफेसर डगलस श्मिट द्वारा इंगित किया गया है, सामग्री प्रदाता डेटा के केंद्रीय भंडार में एक या अधिक अनुप्रयोगों तक पहुंच का प्रबंधन और मध्यस्थता करता है

प्रोग्रामिंग एंड्रॉइड पुस्तक में, सामग्री प्रदाताओं को एक शानदार वेब सेवा के लिए फेकाडे के रूप में उपयोग किया जाता है । यह दृष्टिकोण शुरुआत में Google I / O 2010 के दौरान वर्जील डोबंजांची द्वारा प्रस्तुत किया गया था।

इस प्रकार, स्थानीय SQLite डेटाबेस तक पहुंचने के लिए सामग्री प्रदाताओं का उपयोग करने के बजाय, इसे रिपोजिटरी पैटर्न के रूप में क्यों उपयोग नहीं किया जा रहा है?


आईएमएचओ, एक सामग्रीप्रोवाइडर को डेटासोर्स के रूप में विचार करना बेहतर है, हालांकि आर्किटेक्चर और एंड्रॉइड फ्रेमवर्क के बीच कुछ स्वतंत्रता रखने के लिए डेटा को कई तरीकों से संग्रहीत किया जा सकता है (SQLite डेटाबेस, फ़ाइलें, ...)।

एक Google भंडार वास्तुकला के कुछ नमूने प्रदान करते हैं। उनमें से एक में सामग्री प्रदाता और एक भंडार के साथ वास्तुकला का एक उदाहरण है:

googlesamples/android-architecture/todo-mvp-contentproviders

चयनित अंश:

इसके बाद आप निम्नलिखित प्रदाताओं द्वारा कवर किए गए अतिरिक्त सुविधाओं का समर्थन करने के लिए सामग्री प्रदाताओं का उपयोग कर सकते हैं, निम्नलिखित संभावित लाभ प्रदान करते हैं:

  • आपको अन्य ऐप के साथ अपने ऐप में संग्रहीत डेटा सुरक्षित रूप से साझा करने की अनुमति देता है।
  • अपने ऐप में कस्टम खोजों के लिए समर्थन जोड़ें।
  • अपने ऐप में डेटा तक पहुंचने वाले विजेट विकसित करें।


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

यदि आपके पास एक ऐप है जो पूरी तरह से मंच पर निर्भर करता है, जिसका अर्थ है कि केवल एंड्रॉइड पारिस्थितिक तंत्र के संदर्भ को ध्यान में रखते हैं, तो हां, ContentProvider रिपोजिटरी पैटर्न का कार्यान्वयन है । यहां तर्क यह है कि सामग्री प्रदाता को कुछ चुनौतियों को हल करने के लिए डिज़ाइन किया गया था जो भंडार पैटर्न को हल करना है:

  • यह डेटा परत पर अमूर्तता प्रदान करता है, इसलिए कोड आवश्यक रूप से भंडारण वातावरण पर निर्भर नहीं है
  • हर जगह से कोई प्रत्यक्ष डेटा उपयोग नहीं। आप अपने सभी SQL क्वेरी (या जो कुछ भी) एक ही स्थान पर डाल सकते हैं। जब मैंने पहली बार एक सामग्री प्रदाता को नोब के रूप में कार्यान्वित किया, तो यह मेरे लिए एक रहस्योद्घाटन की तरह था कि मेरा कोड कितना साफ दिख सकता है और मैं कितना सहज परिवर्तन कर सकता हूं
  • डेटा को केंद्रीकृत करता है और इसे कई क्लाइंट्स (अन्य ऐप्स, एक खोज विजेट जैसा कि आप जानते हैं) के बीच साझा करता है और डेटा सुरक्षा के लिए तंत्र प्रदान करता है
  • आप निश्चित रूप से डेटा से संबंधित व्यवहार को परिभाषित कर सकते हैं (एक तरीका ContentObserver का उपयोग करके है)
  • यूनिट परीक्षण / स्वचालित परीक्षण के साथ अपने कोड को व्यवस्थित करने के लिए शुरुआती चरणों से आपको मजबूर करने का यह एक अच्छा तरीका है

यदि आप उपरोक्त सभी पक्षों को भंडार पैटर्न के सिद्धांतों के साथ रखते हैं, तो कुछ गंभीर समानताएं हैं। वे सभी संतुष्ट नहीं हैं, लेकिन मूल विचार समान हैं।

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

tl; डॉ; यदि आपका ऐप आपके एंड्रॉइड डिवाइस पर अलग है तो आप निश्चित रूप से दो अवधारणाओं को मर्ज कर सकते हैं। यदि आपका ऐप बड़े पैमाने पर उपयोग किया जाता है, तो कई प्लेटफ़ॉर्म पर यह आपके क्लीनर तरीके से व्यवस्थित करने के लिए क्लीनर है।


यह एक रूचिकर प्रश्न है। मुझे लगता है कि मेरा पहला जवाब नहीं होगा, सामग्री प्रदाता रिपोजिटरी पैटर्न का कार्यान्वयन नहीं है।

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

आप इंटरफ़ेस के पीछे सामग्री प्रदाता तर्क को छिपाने का एक तरीका कल्पना कर सकते हैं, लेकिन आप सामग्री प्रदाता को करने की अनुमति देने वाली कई अच्छी चीज़ें खो देंगे।

यदि आप एंड्रॉइड आर्किटेक्चर में दिलचस्पी रखते हैं तो मैं आपको इस गीथब प्रोजेक्ट एंड्रॉइड क्लीन आर्किटेक्चर को देखने की सलाह दूंगा। आपको अपनी प्रस्तुति, डोमेन और डेटा परत को अलग करने का एक अच्छा तरीका मिलेगा, और डोमेन और डेटा के बीच संचार एक रिपोजिटरी पैटर्न का उपयोग करके किया जाता है।

उम्मीद है कि यह मदद करेगा!


रिपोजिटरी के रूप में ContentProviders का उपयोग करने में समस्या यह है कि आप अपने मॉडल में एंड्रॉइड फ्रेमवर्क पर निर्भरता जोड़ते हैं। भंडार पैटर्न का उपयोग करने से आप आसानी से नकल, परीक्षण और कार्यान्वयन को प्रतिस्थापित कर सकते हैं।

सही तरीका एक इंटरफेस के तहत ContentProvider को छिपाना होगा, और इस इंटरफ़ेस के माध्यम से डेटा तक पहुंचने वाला मॉडल होगा। इस तरह, आपका कोड मंच से decoupled है।

असल में, ContentProvider I / O स्रोत है जिसे आप अमूर्त करना चाहते हैं।


सामग्री प्रदाता एक Android घटक है, यदि आप इस घटक के साथ भंडार अवधारणा को मिश्रित करते हैं तो गंध अच्छा नहीं होगा, यह आपके आवेदन पर अवरुद्ध निर्भरता बनाता है।


आइए मार्टिन फाउलर (डेव राइस, मैथ्यू फोममेल, एडवर्ड हैट, रॉबर्ट मी और रैंडी स्टाफ़र्ड के साथ ) "सामग्री एंटरप्राइज़ एप्लिकेशन आर्किटेक्चर के पैटर्न" से रिपोजिटरी पैटर्न परिभाषा की तुलना करने की कोशिश करें , जिसे हम ContentProviders बारे में जानते हैं।

किताब कहती है:

डोमेन ऑब्जेक्ट्स एक्सेस करने के लिए संग्रह-जैसे इंटरफ़ेस का उपयोग करके डोमेन और डेटा मैपिंग परतों के बीच एक रिपोजिटरी मध्यस्थता करता है।

महत्वपूर्ण बिट accessing domain objects । तो पहली नज़र में ऐसा लगता है कि भंडार पैटर्न केवल डेटा (क्वेरीिंग) डेटा तक पहुंचने के लिए है। एक ContentProvider साथ, हालांकि, आप न केवल डेटा (डेटा) तक पहुंच सकते हैं बल्कि डेटा को सम्मिलित, अपडेट या हटा सकते हैं। हालांकि, पुस्तक कहती है:

वस्तुओं को रिपोजिटरी से जोड़ा और हटाया जा सकता है, क्योंकि वे वस्तुओं के एक साधारण संग्रह से हो सकते हैं, और रिपोजिटरी द्वारा encapsulated मैपिंग कोड दृश्यों के पीछे उचित संचालन करेगा।

तो, हां रिपोजिटरी और कंटेंटप्रोवाइडर एक ही ऑपरेशन (बहुत उच्च स्तर के दृष्टिकोण) की पेशकश करते प्रतीत होते हैं, हालांकि पुस्तक स्पष्ट रूप simple collection of objects बताती simple collection of objects जो ContentProvider लिए सच नहीं है क्योंकि इसके लिए क्लाइंट से एंड्रॉइड विशिष्ट ContentProvider और Cursor आवश्यकता होती है (जो निश्चित रूप से उपयोग करता है ContentProvider ) के साथ बातचीत करने के लिए।

साथ ही, पुस्तक domain objects और data mapping layers का उल्लेख करती है:

डोमेन और डेटा मैपिंग परतों के बीच एक रिपोजिटरी मध्यस्थता

तथा

कवर के तहत, रिपोजिटरी मेटाडाटा मैपिंग (32 9) को क्वेरी ऑब्जेक्ट (316) के साथ जोड़ती है मेटाडाटा मैपिंग में मेटाडेटा में ऑब्जेक्ट-रिलेशनल मैपिंग का विवरण होता है।

मेटाडेटा मैपिंग का मूल रूप से अर्थ है कि जावा क्लास फ़ील्ड में SQL कॉलम को कैसे मैप करना है।

जैसा कि पहले से ही बताया गया है ContentProvider एक क्वेरी () ऑपरेशन से Cursor ऑब्जेक्ट देता है। मेरे दृष्टिकोण से एक कर्सर डोमेन ऑब्जेक्ट नहीं है। इसके अलावा, कर्सर से डोमेन ऑब्जेक्ट पर मैपिंग क्लाइंट द्वारा किया जाना चाहिए (जो ContentProvider का उपयोग करता है)। तो मेरे दृष्टिकोण से ContentProvider में डेटा मैपिंग पूरी तरह गायब है। इसके अलावा, डोमेन ऑब्जेक्ट (डेटा) प्राप्त करने के लिए क्लाइंट को ContentResolver भी उपयोग करना पड़ सकता है। मेरी राय में यह एपीआई पुस्तक की परिभाषा के साथ एक स्पष्ट विरोधाभास है:

रिपोजिटरी डोमेन और डेटा मैपिंग परतों के बीच एक स्वच्छ अलगाव और एक तरफा निर्भरता प्राप्त करने के उद्देश्य का भी समर्थन करता है

अगला चलो रेपोजिटरी पैटर्न के मूल विचार पर ध्यान केंद्रित करते हैं:

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

ContentProvider को एक यूआरआई (स्ट्रिंग) की आवश्यकता होती है। तो यह वास्तव में एक "ऑब्जेक्ट उन्मुख तरीका" नहीं है। इसके अलावा एक ContentProvider को projection और एक where-clause आवश्यकता हो सकती है।

तो कोई तर्क दे सकता है कि एक यूआरआई स्ट्रिंग कुछ प्रकार का encapsulation है क्योंकि क्लाइंट उदाहरण के लिए विशिष्ट एसक्यूएल कोड लिखने के बजाय इस स्ट्रिंग का उपयोग कर सकते हैं:

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

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

उदाहरण के लिए, नाम से व्यक्ति वस्तुओं को ढूंढने के लिए हम पहले एक मानदंड वस्तु बनाते हैं, प्रत्येक व्यक्तिगत मानदंड को इस तरह सेट करते हैं: मानदंड.equals (Person.LAST_NAME, "Fowler"), और मानदंड। (Person.FIRST_NAME, "M")। फिर हम डोमेन ऑब्जेक्ट्स की एक सूची वापस करने के लिए repository.matching (मानदंड) का आह्वान करते हैं जो अंतिम नाम फाउलर वाले लोगों का प्रतिनिधित्व करते हैं और एम के साथ शुरू होने वाला पहला नाम।

जैसा कि आपने पहले से ही कहा है (आपके प्रश्न में) रिपोजिटरी विभिन्न डेटा स्रोतों को एक कार्यान्वयन विवरण के रूप में छिपाने के लिए भी उपयोगी है जिसे क्लाइंट के बारे में पता नहीं है। यह ContentProviders के लिए सच है और पुस्तक में निर्दिष्ट है:

रिपोजिटरी के लिए ऑब्जेक्ट स्रोत बिल्कुल एक रिलेशनल डेटाबेस नहीं हो सकता है, जो ठीक है क्योंकि रिपोजिटरी विशेष रणनीति ऑब्जेक्ट्स के माध्यम से डेटा-मैपिंग घटक के प्रतिस्थापन के लिए खुद को काफी आसानी से उधार देती है। इस कारण से यह कई डेटाबेस स्कीमा या डोमेन ऑब्जेक्ट्स के स्रोतों के साथ सिस्टम में विशेष रूप से उपयोगी हो सकता है, साथ ही परीक्षण के दौरान जब विशेष रूप से इन-मेमोरी ऑब्जेक्ट्स का उपयोग गति के लिए वांछनीय है।

तथा

चूंकि रिपोजिटरी का इंटरफ़ेस डेटा स्रोत के बारे में जागरूकता से डोमेन परत को ढालता है, इसलिए हम ग्राहकों से किसी भी कॉल को बदले बिना रिपोजिटरी के अंदर क्वेरीिंग कोड के कार्यान्वयन को दोबारा कर सकते हैं। दरअसल, डोमेन कोड को डोमेन ऑब्जेक्ट्स के स्रोत या गंतव्य के बारे में परवाह नहीं है।

तो निष्कर्ष निकालना: मार्टिन फाउलर एट अल की कुछ परिभाषाएं। पुस्तक एक ContentProvider के एपीआई से मेल खाता है (यदि आप इस तथ्य को अनदेखा करते हैं कि पुस्तक ऑब्जेक्ट उन्मुख पर जोर देती है):

  • इस तथ्य को छुपाता है कि एक भंडार / सामग्री प्रदाता के पास विभिन्न डेटा स्रोत हैं
  • क्लाइंट को डेटासॉर विशिष्ट डीएसएल जैसे एसक्यूएल में कभी भी एक प्रश्न लिखना नहीं है। यह ContentProvider के लिए सच है यदि हम यूआरआई को डेटासोर्स विशिष्ट नहीं मानते हैं।
  • दोनों, रिपोजिटरी और कंटेंटप्रोवाइडर के पास, "उच्च स्तर" संचालन का सेट होता है: डेटा को पढ़ें, डालें, अपडेट करें और हटाएं (यदि आप इस तथ्य को अनदेखा करते हैं कि फाउलर ऑब्जेक्ट उन्मुख और ऑब्जेक्ट्स के संग्रह के बारे में बहुत कुछ बोलता है जबकि ContentProvider कर्सर और ContentValues ​​का उपयोग करता है)

हालांकि, ContentProvider वास्तव में पुस्तक में वर्णित भंडार पैटर्न के कुछ महत्वपूर्ण बिंदुओं को याद करता है:

  • चूंकि ContentProvider यूआरआई (जहां खंड के लिए भी स्ट्रिंग) का उपयोग करता है, क्लाइंट मिलान मानदंड वस्तुओं का पुन: उपयोग नहीं कर सकता है। यह ध्यान रखना एक महत्वपूर्ण बात है। पुस्तक स्पष्ट रूप से कहती है कि भंडार पैटर्न उपयोगी है "कई डोमेन ऑब्जेक्ट प्रकारों और कई संभावित प्रश्नों वाली एक बड़ी प्रणाली में, रिपोजिटरी सभी क्वेरीिंग से निपटने के लिए आवश्यक कोड की मात्रा को कम कर देता है"। दुर्भाग्यवश, ContentProvider में मानदंड जैसी वस्तुएं नहीं हैं criteria.equals(Person.LAST_NAME, "Fowler") जिसे पुन: उपयोग किया जा सकता है और मिलान मानदंडों को लिखने के लिए उपयोग किया जा सकता है (क्योंकि आपको स्ट्रिंग का उपयोग करना है)।
  • ContentProvider पूरी तरह से डेटा मैपिंग को याद करता है क्योंकि यह Cursor देता है। यह बहुत बुरा है क्योंकि एक क्लाइंट (जो डेटा तक पहुंचने के लिए ContentProvider का उपयोग करता है) को डोमेन ऑब्जेक्ट में कर्सर का मैपिंग करना होता है। इसके अलावा, इसका मतलब है कि क्लाइंट को कॉलम के नाम जैसे भंडार आंतरिक का ज्ञान है। "रिपोजिटरी कोड में पठनीयता और स्पष्टता में सुधार के लिए एक अच्छा तंत्र हो सकता है जो व्यापक रूप से पूछताछ का उपयोग करता है।" यह निश्चित रूप से ContentProviders के लिए सच नहीं है।

तो नहीं, एक ContentProvider "एंटरप्राइज़ एप्लिकेशन आर्किटेक्चर के पैटर्न" पुस्तक में परिभाषित रेपोजिटरी पैटर्न का कार्यान्वयन नहीं है क्योंकि यह ऊपर दी गई कम से कम दो आवश्यक चीजों को याद करता है।

साथ ही, कृपया ध्यान दें कि पुस्तक का नाम पहले ही सुझाता है, भंडार पैटर्न का उपयोग एंटरप्राइज़ एप्लिकेशन के लिए किया जाना है जहां आप बहुत सारे प्रश्न पूछते हैं।

एंड्रॉइड डेवलपर्स शब्द "रिपोजिटरी पैटर्न" का उपयोग करते हैं लेकिन वास्तव में फॉउलर एट अल द्वारा वर्णित "मूल" पैटर्न का अर्थ नहीं है। (प्रश्नों के लिए मानदंडों की उच्च पुन: प्रयोज्यता) बल्कि अंतर्निहित डेटा स्रोत (एसक्यूएल, क्लाउड, जो कुछ भी) और डोमेन ऑब्जेक्ट मैपिंग को छिपाने के लिए एक इंटरफेस का मतलब है।

यहां और अधिक: http://hannesdorfmann.com/android/evolution-of-the-repository-pattern





android-mvp