किसी वस्तु को अपने तरीके से या किसी अन्य वर्ग के माध्यम से सहेजना?


38

यदि मैं किसी ऑब्जेक्ट को सहेजना और पुनः प्राप्त करना चाहता हूं, तो क्या मुझे इसे संभालने के लिए कोई अन्य वर्ग बनाना चाहिए, या कक्षा में ही ऐसा करना बेहतर होगा? या शायद दोनों का मिश्रण?

OOD प्रतिमान के अनुसार किसकी सिफारिश की जाती है?

उदाहरण के लिए

Class Student
{
    public string Name {set; get;}
    ....
    public bool Save()
    {
        SqlConnection con = ...
        // Save the class in the db
    }
    public bool Retrieve()
    {
         // search the db for the student and fill the attributes
    }
    public List<Student> RetrieveAllStudents()
    {
         // this is such a method I have most problem with it 
         // that an object returns an array of objects of its own class!
    }
}

बनाम। (मुझे पता है कि निम्नलिखित की सिफारिश की गई है, हालांकि यह मुझे Studentवर्ग के सामंजस्य के खिलाफ थोड़ा सा लगता है )

Class Student { /* */ }
Class DB {
  public bool AddStudent(Student s)
  {

  }
  public Student RetrieveStudent(Criteria)
  {
  } 
  public List<Student> RetrieveAllStudents()
  {
  }
}

उन्हें कैसे मिलाया जाए?

   Class Student
    {
        public string Name {set; get;}
        ....
        public bool Save()
        {
            /// do some business logic!
            db.AddStudent(this);
        }
        public bool Retrieve()
        {
             // build the criteria 
             db.RetrieveStudent(criteria);
             // fill the attributes
        }
    }

3
आपको सक्रिय रिकॉर्ड पैटर्न पर कुछ शोध करना चाहिए, जैसे कि यह प्रश्न या यह एक
एरिक किंग

@gnat, मैंने सोचा कि यह पूछना बेहतर है कि क्या राय आधारित है, फिर "पेशेवरों और विपक्ष" को जोड़ा गया है और इसे हटाने के लिए कोई समस्या नहीं है, लेकिन वास्तव में मेरा मतलब है OOD प्रतिमान के बारे में जो सिफारिश की गई है
अहमद

3
कोई सही उत्तर नहीं है। यह आपकी आवश्यकताओं, आपकी प्राथमिकताओं पर निर्भर करता है कि आपकी कक्षा का उपयोग कैसे किया जाए और आप अपनी परियोजना को कहां देखते हैं। केवल सही OO बात यह है कि आप ऑब्जेक्ट के रूप में सहेज और पुनर्प्राप्त कर सकते हैं।
डंक

जवाबों:


34

एकल उत्तरदायित्व सिद्धांत , सरोकारों और कार्यात्मक सामंजस्य का पृथक्करण । यदि आप इन अवधारणाओं को पढ़ते हैं, तो आपको जो उत्तर मिलता है वह है: उन्हें अलग करना

Student"DB" वर्ग (या StudentRepositoryअधिक लोकप्रिय सम्मेलनों का पालन करने के लिए) से अलग करने का एक सरल कारण आपको अपने "व्यावसायिक नियमों" को बदलने की अनुमति देता है, जो Studentकक्षा में मौजूद है , बिना कोड को प्रभावित किए, जो दृढ़ता के लिए जिम्मेदार है, और इसके विपरीत- विपरीत।

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

व्यावसायिक नियमों और दृढ़ता को एक साथ मिलाकर, या तो आपके पहले उदाहरण के रूप में एक एकल वर्ग, या की DBनिर्भरता के रूप में Student, आप दो बहुत अलग चिंताओं को जोड़ रहे हैं। ऐसा लग सकता है कि वे एक साथ हैं; वे सामंजस्यपूर्ण लग रहे हैं क्योंकि वे एक ही डेटा का उपयोग करते हैं। लेकिन यहाँ एक बात है: सामंजस्य केवल प्रक्रियाओं द्वारा साझा किए गए डेटा द्वारा नहीं मापा जा सकता है, आपको उस अमूर्त के स्तर पर भी विचार करना चाहिए जिस पर वे मौजूद हैं। वास्तव में, आदर्श प्रकार के सामंजस्य का वर्णन इस प्रकार है:

कार्यात्मक सामंजस्य तब होता है जब किसी मॉड्यूल के भागों को समूहीकृत किया जाता है क्योंकि वे सभी मॉड्यूल के एक एकल अच्छी तरह से परिभाषित कार्य में योगदान करते हैं।

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

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


11
आह, लेकिन Studentवर्ग ठीक से समझाया जाना चाहिए, हाँ? फिर एक बाहरी वर्ग निजी राज्य की दृढ़ता का प्रबंधन कैसे कर सकता है? एनओसी और एसआरपी के खिलाफ एनकैप्सुलेशन को संतुलित किया जाना चाहिए, लेकिन ट्रेडऑफ को ध्यान से तौले बिना बस दूसरे पर चुनना शायद गलत है। इस पहेली का एक संभावित समाधान पैकेज-प्राइवेट एक्सेसर्स का उपयोग करने के लिए दृढ़ता कोड का उपयोग करना है।
आमोन

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

4
यह दावा कि SRP कार्यक्रमों को बनाए रखना आसान बनाता है, सबसे अच्छे रूप में संदिग्ध है। एसआरपी की समस्या यह है कि अच्छी तरह से नामित कक्षाओं का एक संग्रह होने के बजाय, जहां नाम सब कुछ बताता है कि कक्षा क्या कर सकती है और क्या नहीं कर सकती है (दूसरे शब्दों में यह समझना आसान है कि जो आसानी से बनाए रखता है) आप सैकड़ों / के साथ समाप्त होते हैं हजारों वर्ग जिन्हें लोगों को एक अद्वितीय नाम चुनने के लिए एक थिसॉरस का उपयोग करने की आवश्यकता थी, कई नाम समान हैं, लेकिन काफी नहीं हैं और उन सभी के माध्यम से छंटनी की जा रही है। IOW, बिल्कुल भी नहीं, आईएमओ।
डंक

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

5
@ डंक OOD सिद्धांतों के रूप में कहा जा सकता है: "सिद्धांत रूप में, एक्स, वाई और जेड के कारण ऐसा करना बेहतर है"। इसका मतलब यह नहीं है कि इसे हमेशा लागू किया जाना चाहिए; लोगों को व्यावहारिक होना चाहिए और व्यापार-नापसंद करना होगा। बड़ी परियोजनाओं में, लाभ ऐसे होते हैं जो आमतौर पर सीखने की अवस्था से बाहर निकल जाते हैं जिसे आप बोलते हैं - लेकिन निश्चित रूप से, यह अधिकांश लोगों के लिए वास्तविकता नहीं है, और इसलिए इसे भारी रूप से लागू नहीं किया जाना चाहिए। हालांकि, यहां तक ​​कि हल्के अनुप्रयोगों एसआरपी में, मुझे लगता है कि हम दोनों सहमत हो सकते हैं कि व्यावसायिक नियमों से दृढ़ता को अलग करने से हमेशा इसकी लागत से परे लाभ मिलता है (शायद फेंक-दूर कोड के लिए छोड़कर)।
मिशेल हेनरिक

10

दोनों दृष्टिकोण एकल जिम्मेदारी सिद्धांत का उल्लंघन करते हैं। आप पहले संस्करण Studentको कई जिम्मेदारियों के लिए कक्षा देते हैं और इसे एक विशिष्ट डीबी एक्सेस तकनीक से जोड़ते हैं। दूसरा एक विशाल DBवर्ग की ओर जाता है जो न केवल छात्रों के लिए, बल्कि आपके कार्यक्रम में किसी अन्य प्रकार की डेटा ऑब्जेक्ट के लिए जिम्मेदार होगा। EDIT: आपका तीसरा दृष्टिकोण सबसे बुरा है, क्योंकि यह DB वर्ग और वर्ग के बीच चक्रीय निर्भरता बनाता है Student

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


धन्यवाद, मैंने अपना जवाब संशोधित किया, तीसरे दृष्टिकोण के बारे में क्या? वैसे भी मुझे लगता है कि यहाँ बिंदु अलग परतों के बारे में है
अहमद

डीबी के बजाय स्टूडेंट रिपॉजिटरी का उपयोग करने के लिए कुछ मुझे भी सुझाते हैं (पता नहीं क्यों? शायद फिर से एकल जिम्मेदारी) लेकिन मुझे अभी भी नहीं मिल सकता है कि प्रत्येक वर्ग के लिए अलग-अलग रिपॉजिटरी क्यों? अगर इसकी सिर्फ एक डेटा एक्सेस लेयर है तो स्टैटिक यूटिलिटी फंक्शंस के अधिक समूह हैं और एक साथ हो सकते हैं, नहीं? शायद तब यह इतना गंदा और भीड़-भाड़ वाला वर्ग बन गया था (मेरी अंग्रेजी के लिए खेद है)
अहमद

1
@ अहमदाबाद: कारणों की एक जोड़ी है, और कुछ पेशेवरों और विचार करने के लिए विपक्ष। यह एक पूरी किताब भर सकता है। इसके पीछे का तर्क आपके कार्यक्रमों की परीक्षणशीलता, स्थिरता और दीर्घकालिक उद्दण्डता को उबालता है, खासकर जब उनके पास लंबे समय तक चलने वाला जीवन चक्र होता है।
Doc Brown

क्या किसी ने ऐसी परियोजना पर काम किया है जहां डीबी प्रौद्योगिकी में महत्वपूर्ण परिवर्तन हुआ था? (बड़े पैमाने पर पुनर्लेखन के बिना?) मैंने नहीं किया है। यदि हां, तो एसआरपी का पालन किया गया, जैसा कि सुझाव दिया गया है कि उस डीबी से बंधे होने से बचने के लिए, काफी मदद करें?
user949300

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

3

काफी कुछ पैटर्न हैं जो डेटा दृढ़ता के लिए उपयोग किए जा सकते हैं। कार्य पैटर्न की इकाई है , रिपॉजिटरी पैटर्न है, कुछ अतिरिक्त पैटर्न हैं जिनका उपयोग रिमोट फेकड की तरह किया जा सकता है, और इसी तरह और भी।

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

एक साइड नोट के रूप में: आपके उदाहरण में RetrieveStudent, AddStudent को स्टैटिक मेथड होना चाहिए (क्योंकि वे उदाहरण-निर्भर नहीं हैं)।

इन-क्लास सेव / लोड तरीकों के होने का एक और तरीका है:

class Animal{
    public string Name {get; set;}
    public void Save(){...}
    public static Animal Load(string name){....}
    public static string[] GetAllNames(){...} // if you just want to list them
    public static Animal[] GetAllAnimals(){...} // if you actually need to retrieve them all
}

व्यक्तिगत रूप से मैं इस तरह के दृष्टिकोण का उपयोग केवल छोटे अनुप्रयोगों में ही करूँगा, संभवतः निजी उपयोग के लिए उपकरण या जहाँ मैं मज़बूती से यह अनुमान लगा सकता हूँ कि मेरे पास वस्तुओं को सहेजने या लोड करने की तुलना में अधिक जटिल उपयोग के मामले नहीं होंगे।

व्यक्तिगत रूप से भी, यूनिट ऑफ़ वर्क पैटर्न देखें। जब आप इसे जानते हैं, तो यह वास्तव में छोटे और बड़े दोनों मामलों में अच्छा है। उदाहरण के लिए EntityFramework या RavenDB को नाम देने के लिए इसे बहुत सारे चौखटे / एपिस द्वारा समर्थित किया गया है।


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

आप निश्चित रूप से सही हैं, मैंने मूल प्रश्न के आधार पर बहुत सी धारणाएँ बनाई हैं।
गेरिनो

धन्यवाद, मुझे लगता है कि सर्वश्रेष्ठ दृष्टिकोण परतों का उपयोग कर रहा है जैसा कि रिपॉजिटरी पैटर्न में उल्लेख किया गया है
अहमद

1

यदि यह एक बहुत ही सरल ऐप है, जहाँ वस्तु अधिक या कम से कम डेटास्टोर और वीज़ा-वर्सा से जुड़ी होती है (अर्थात डेटास्टोर की संपत्ति के रूप में सोचा जा सकता है), तो उस वर्ग के लिए एक .save () विधि होने से समझ में आ सकती है।

लेकिन मुझे लगता है कि यह बहुत असाधारण होगा।

बल्कि, आमतौर पर कक्षा को अपने डेटा और उसकी कार्यक्षमता (एक अच्छे OO नागरिक की तरह) को प्रबंधित करने देना बेहतर होता है, और दृढ़ता तंत्र को किसी अन्य वर्ग, या कक्षाओं के सेट से बाहर करना।

अन्य विकल्प एक दृढ़ता ढांचे का उपयोग करना है जो दृढ़ता को घोषणात्मक रूप से परिभाषित करता है (जैसे एनोटेशन के साथ), लेकिन यह अभी भी दृढ़ता को बाहरी बना रहा है।


-1
  • उस वर्ग पर एक विधि को परिभाषित करें जो ऑब्जेक्ट को क्रमबद्ध करता है, और बाइट्स का एक क्रम देता है जिसे आप डेटाबेस में डाल सकते हैं या जो कुछ भी खोल सकते हैं
  • उस ऑब्जेक्ट के लिए एक कंस्ट्रक्टर रखें जो इनपुट के रूप में बाइट्स का ऐसा क्रम लेता है

RetrieveAllStudents()विधि के बारे में , आपकी भावना सही है, यह वास्तव में गलत है, क्योंकि आपके पास छात्रों की कई अलग-अलग सूचियां हो सकती हैं। बस Studentवर्ग के बाहर सूची (ओं) को क्यों न रखें ?


तुम्हें पता है कि मैंने कुछ PHP फ्रेमवर्क में इस तरह के ट्रेंड को देखा है उदाहरण के लिए Laravel अगर आप इसे जानते हैं। मॉडल डेटाबेस से जुड़ा हुआ है और वस्तुओं की एक श्रृंखला भी वापस कर सकता है।
अहमद
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.