अपने माता-पिता के लिए बच्चे के संदर्भ को इनिशियलाइज़ करने का सबसे अच्छा तरीका क्या है?


35

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

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

ध्यान दें कि मेरे कुछ चाइल्ड क्लास कंस्ट्रक्टर पैरामीटर (माता-पिता के अलावा) लेते हैं, भले ही मैं हमेशा किसी को नहीं दिखाता।

  1. माता-पिता को स्थापित करने और उसी माता-पिता को जोड़ने के लिए कॉलर जिम्मेदार है।

    class Child {
      public Child(Parent parent) {Parent=parent;}
      public Parent Parent {get; private set;}
    }
    class Parent {
      // singleton child
      public Child Child {get; set;}
      //children
      private List<Child> _children = new List<Child>();
      public List<Child> Children { get {return _children;} }
    }
    

    डाउनसाइड: अभिभावक को सेट करना उपभोक्ता के लिए दो चरणों वाली प्रक्रिया है।

    var child = new Child(parent);
    parent.Children.Add(child);
    

    नकारात्मक पक्ष: त्रुटि प्रवण। कॉलर बच्चे को अलग-अलग माता-पिता से जोड़ सकता है, जिसका उपयोग बच्चे को शुरू करने के लिए किया गया था।

    var child = new Child(parent1);
    parent2.Children.Add(child);
    
  2. माता-पिता सत्यापित करता है कि कॉलर माता-पिता के लिए बच्चे को जोड़ता है जिसके लिए आरंभीकृत किया गया था।

    class Child {
      public Child(Parent parent) {Parent = parent;}
      public Parent Parent {get; private set;}
    }
    class Parent {
      // singleton child
      private Child _child;
      public Child Child {
        get {return _child;}
        set {
          if (value.Parent != this) throw new Exception();
          _child=value;
        }
      }
      //children
      private List<Child> _children = new List<Child>();
      public ReadOnlyCollection<Child> Children { get {return _children;} }
      public void AddChild(Child child) {
        if (child.Parent != this) throw new Exception();
        _children.Add(child);
      }
    }
    

    डाउनसाइड: कॉलर को अभी भी पैरेंट सेट करने के लिए दो-चरण की प्रक्रिया है।

    डाउनसाइड: रनटाइम चेकिंग - प्रदर्शन को कम करता है और प्रत्येक ऐड / सेटर में कोड जोड़ता है।

  3. जब बच्चे को माता-पिता में जोड़ा जाता है / सौंपा जाता है, तो माता-पिता बच्चे के माता-पिता के संदर्भ (खुद को) निर्धारित करते हैं। जनक सेटर आंतरिक है।

    class Child {
      public Parent Parent {get; internal set;}
    }
    class Parent {
      // singleton child
      private Child _child;
      public Child Child {
        get {return _child;}
        set {
          value.Parent = this;
          _child = value;
        }
      }
      //children
      private List<Child> _children = new List<Child>();
      public ReadOnlyCollection<Child> Children { get {return _children;} }
      public void AddChild(Child child) {
        child.Parent = this;
        _children.Add(child);
      }
    }
    

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

  4. पैरेंट फैक्ट्री ऐड मेथड्स को उजागर करता है ताकि एक बच्चे का हमेशा पेरेंट रेफरेंस हो। बाल संवार आंतरिक है। जनक सेटर निजी है।

    class Child {
      internal Child(Parent parent, init-params) {Parent = parent;}
      public Parent Parent {get; private set;}
    }
    class Parent {
      // singleton child
      public Child Child {get; private set;}
      public void CreateChild(init-params) {
          var child = new Child(this, init-params);
          Child = value;
      }
      //children
      private List<Child> _children = new List<Child>();
      public ReadOnlyCollection<Child> Children { get {return _children;} }
      public Child AddChild(init-params) {
        var child = new Child(this, init-params);
        _children.Add(child);
        return child;
      }
    }
    

    डाउनसाइड: जैसे इनिशियलाइज़ सिंटैक्स का उपयोग नहीं कर सकते new Child(){prop = value}। इसके बजाय करना होगा:

    var c = parent.AddChild(); 
    c.prop = value;
    

    डाउनसाइड: ऐड-फैक्ट्री विधियों में चाइल्ड कंस्ट्रक्टर के मापदंडों की नकल करना है।

    नकारात्मक पक्ष: एक एकल बच्चे के लिए एक संपत्ति सेटर का उपयोग नहीं कर सकते। यह लंगड़ा लगता है कि मुझे मूल्य निर्धारित करने के लिए एक विधि की आवश्यकता है लेकिन एक संपत्ति पाने वाले के माध्यम से रीड एक्सेस प्रदान करें। यह लोप हो गया है।

  5. बाल अपने निर्माता में संदर्भित माता-पिता से खुद को जोड़ता है। बाल चोर जनता है। माता-पिता से कोई भी सार्वजनिक पहुंच नहीं है।

    //singleton
    class Child{
      public Child(ParentWithChild parent) {
        Parent = parent;
        Parent.Child = this;
      }
      public ParentWithChild Parent {get; private set;}
    }
    class ParentWithChild {
      public Child Child {get; internal set;}
    }
    
    //children
    class Child {
      public Child(ParentWithChildren parent) {
        Parent = parent;
        Parent._children.Add(this);
      }
      public ParentWithChildren Parent {get; private set;}
    }
    class ParentWithChildren {
      internal List<Child> _children = new List<Child>();
      public ReadOnlyCollection<Child> Children { get {return _children;} }
    }
    

    डाउनसाइड: कॉलिंग सिंटैक्स महान नहीं है। आम तौर addपर कोई अभिभावक को इस तरह से एक वस्तु बनाने के बजाय एक विधि कहता है :

    var parent = new ParentWithChildren();
    new Child(parent); //adds child to parent
    new Child(parent);
    new Child(parent);
    

    और इस तरह एक वस्तु बनाने के बजाय एक संपत्ति सेट करता है:

    var parent = new ParentWithChild();
    new Child(parent); // sets parent.Child
    

...

मैंने अभी सीखा कि एसई कुछ व्यक्तिपरक प्रश्नों की अनुमति नहीं देता है और स्पष्ट रूप से यह एक व्यक्तिपरक प्रश्न है। लेकिन, शायद यह एक अच्छा व्यक्तिपरक सवाल है।


14
सबसे अच्छा अभ्यास यह है कि बच्चों को अपने माता-पिता के बारे में पता नहीं होना चाहिए।
तेलेस्टिन


2
@Telastyn मैं मदद नहीं कर सकता लेकिन गाल में जीभ के रूप में पढ़ा, और यह प्रफुल्लित करने वाला है। इसके अलावा पूरी तरह से मृत खूनी सटीक। स्टीवन, देखने के लिए शब्द "एसाइक्लिक" है क्योंकि वहाँ बहुत सारे साहित्य हैं, इस पर आपको ग्राफ एसाइक्लिक को यदि संभव हो तो क्यों बनाना चाहिए।
जिमी हॉफ

10
@Telastyn आपको पेरेंटिंग पर उस टिप्पणी का उपयोग करने की कोशिश करनी चाहिए। Stackexchange
Fabio Marcolini

2
हम्म। पता नहीं कैसे एक पोस्ट स्थानांतरित करने के लिए (एक झंडा नियंत्रण नहीं है)। मैंने प्रोग्रामर को फिर से पोस्ट किया क्योंकि किसी ने मुझे बताया कि यह वहां से था।
स्टीवन ब्रॉशर

जवाबों:


19

मैं किसी भी परिदृश्य से दूर रहूँगा जो आवश्यक रूप से बच्चे को माता-पिता के बारे में जानने की आवश्यकता है।

घटनाओं के माध्यम से बच्चे से माता-पिता तक संदेश भेजने के तरीके हैं। इस तरह, माता-पिता को जोड़ने पर, बस एक ऐसी घटना के लिए पंजीकरण करना होता है जो बच्चे को ट्रिगर करता है, बिना बच्चे को सीधे माता-पिता के बारे में पता होना चाहिए। आखिरकार, यह संभवतः माता-पिता के बारे में जानने वाले बच्चे का इच्छित उपयोग है, ताकि कुछ प्रभाव में माता-पिता का उपयोग करने में सक्षम हो सके। सिवाय आप यह नहीं चाहेंगे कि बच्चा माता-पिता का काम कर रहा है, इसलिए वास्तव में आप क्या करना चाहते हैं, बस माता-पिता को बताएं कि कुछ हुआ है। इसलिए, आपको बच्चे को संभालने की एक घटना है, जिसका माता-पिता लाभ उठा सकते हैं।

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

उम्मीद है की वो मदद करदे!


6
" किसी भी परिदृश्य से दूर रहना चाहिए जो आवश्यक रूप से बच्चे को माता-पिता के बारे में जानने की आवश्यकता है " - क्यों? आपका उत्तर इस धारणा पर टिका है कि वृत्ताकार वस्तु रेखांकन एक बुरा विचार है। हालांकि यह कभी-कभी ऐसा होता है (उदाहरण के लिए जब मेमोरी को मैनेज करना भोले-भाले-गिनती के माध्यम से - सी # में मामला नहीं), तो यह सामान्य रूप से बुरी बात नहीं है। विशेष रूप से, ऑब्जर्वर पैटर्न (जो अक्सर घटनाओं को फैलाने के लिए उपयोग किया जाता है) में ऑब्जर्वेबल ( Child) पर्यवेक्षकों के एक सेट ( ) को बनाए रखना शामिल होता है Parent, जो एक पीछे की ओर (और अपने स्वयं के कई मुद्दों का परिचय) में परिपत्रता को फिर से प्रस्तुत करता है।
आमोन

1
क्योंकि चक्रीय निर्भरता का मतलब है कि आपके कोड को इस तरह से संरचित करना कि आपके पास एक के बिना दूसरा न हो। माता-पिता-बच्चे के संबंध की प्रकृति के अनुसार, उन्हें अलग-अलग इकाइयाँ होनी चाहिए अन्यथा आप दो कसकर युग्मित वर्ग होने का जोखिम उठाते हैं जो एक ही विशाल वर्ग हो सकता है जिसमें एक सूची हो सकती है जिसमें सभी सावधान देखभाल के लिए इसकी डिजाइन में डाल दिया गया है। मैं यह देखने में विफल हूं कि ऑब्जर्वर पैटर्न इस तथ्य के अलावा माता-पिता के बच्चे के समान है कि एक वर्ग में कई अन्य लोगों के संदर्भ हैं। मेरे लिए माता-पिता-बच्चे एक माता-पिता हैं जो बच्चे पर एक मजबूत निर्भरता रखते हैं, लेकिन उलटा नहीं।
नील

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

@ नील: वस्तु उदाहरणों की पारस्परिक निर्भरता कई डेटा मॉडल का एक स्वाभाविक हिस्सा है। एक कार के यांत्रिक सिमुलेशन में, कार के विभिन्न हिस्सों को एक-दूसरे पर बल संचारित करने की आवश्यकता होगी; यह आमतौर पर कार के सभी हिस्सों को बेहतर ढंग से नियंत्रित करता है, सिमुलेशन इंजन को "माता-पिता" वस्तु के रूप में मानता है, सभी घटकों के बीच चक्रीय निर्भरता होने से, लेकिन अगर घटक माता-पिता के बाहर से किसी भी उत्तेजना का जवाब देने में सक्षम हैं। अगर माता-पिता को इस बारे में जानने की जरूरत है तो ऐसी उत्तेजनाओं के लिए माता-पिता को सूचित करने का एक तरीका होगा।
सुपरकैट

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

10

मुझे लगता है कि आपका विकल्प 3 सबसे साफ हो सकता है। आप ने लिखा।

नकारात्मक पक्ष: बच्चा बिना माता-पिता के संदर्भ के बनाया जाता है।

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

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


यदि एक बच्चे की वस्तु माता-पिता के बिना कुछ भी उपयोगी नहीं कर सकती है, तो एक माता-पिता के बिना एक बच्चे की वस्तु शुरू करने के लिए इसे एक SetParentविधि की आवश्यकता होगी जो या तो मौजूदा बच्चे के माता-पिता को बदलने के लिए समर्थन करने की आवश्यकता होगी (जो करना मुश्किल हो सकता है और / या निरर्थक) या केवल एक बार कॉल करने योग्य होगा। ऐसी स्थितियों को समुच्चय के रूप में तैयार करना (जैसा कि माइक ब्राउन सुझाव देते हैं) बच्चों को बिना माता-पिता के शुरू करने से बहुत बेहतर हो सकता है।
सुपरकैट

यदि उपयोग मामला एक बार भी कुछ के लिए कहता है, तो डिजाइन को हमेशा इसके लिए अनुमति देनी चाहिए। फिर, उस क्षमता को विशेष परिस्थितियों तक सीमित करना आसान है। ऐसी क्षमता को बाद में जोड़ना आमतौर पर असंभव है। सबसे अच्छा समाधान विकल्प 3 है। संभवतः माता-पिता और बच्चे के बीच एक तीसरे, "संबंध" वस्तु के साथ ऐसा है कि [अभिभावक] ---> [संबंध (माता-पिता बच्चे का मालिक है]] <--- [बच्चा]। यह कई [रिलेशनशिप] इंस्टेंस जैसे कि [चाइल्ड] ---> [रिलेशनशिप (चाइल्ड पैरेंट के स्वामित्व में है)] को भी अनुमति देता है।
DocSalvager

3

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

तो यह आपके परिदृश्य चार की तरह सबसे अधिक होगा, जहां माता-पिता अपने बच्चों को ठीक से शुरू करने और संग्रह में जोड़ने के लिए किसी भी आवश्यक पैरामीटर को स्वीकार करने के लिए अपने बच्चों को बनाने के लिए एक विधि को उजागर करते हैं।


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

3

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

var q2N3904 = new TransistorSpec(TransistorType.NPN, 0.691, 40);
var idealResistor4K7 = new IdealResistorSpec(4700.0);
var idealResistor47K = new IdealResistorSpec(47000.0);

var Q1 = Circuit.AddComponent(q2N3904);
var Q2 = Circuit.AddComponent(q2N3904);
var R1 = Circuit.AddComponent(idealResistor4K7);
var R2 = Circuit.AddComponent(idealResistor4K7);
var R3 = Circuit.AddComponent(idealResistor47K);
var R4 = Circuit.AddComponent(idealResistor47K);

ध्यान दें कि सिम्युलेटर को बाल-निर्माता ऑब्जेक्ट के किसी भी संदर्भ को बनाए रखने की आवश्यकता नहीं है, और AddComponentसिम्युलेटर द्वारा बनाए गए ऑब्जेक्ट के संदर्भ को वापस नहीं किया जाएगा, बल्कि एक ऑब्जेक्ट जो एक दृश्य का प्रतिनिधित्व करता है। यदि AddComponentविधि सामान्य है, तो दृश्य ऑब्जेक्ट में घटक-विशिष्ट फ़ंक्शन शामिल हो सकते हैं लेकिन उन सदस्यों को उजागर नहीं करेंगे, जो माता-पिता अनुलग्नक का प्रबंधन करने के लिए उपयोग करते हैं।


2

महान लिस्टिंग। मुझे नहीं पता कि कौन सी विधि "सर्वश्रेष्ठ" है, लेकिन यहां सबसे अधिक अभिव्यंजक विधियों को खोजने के लिए एक है।

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

शायद आपको मिल जाए addChild()। हो सकता है आप की तरह कुछ मिलता है addChildren(List<Child>)या addChildrenNamed(List<String>)या loadChildrenFrom(String)या newTwins(String, String)या Child.replicate(int)

यदि आपकी समस्या वास्तव में एक-से-कई संबंधों को मजबूर करने के बारे में है, तो शायद आपको चाहिए

  • इसे बसने वालों में मजबूर करें, जिससे भ्रम या थ्रो-क्लॉस हो सकता है
  • आप बसने वालों को हटाते हैं और विशेष प्रतिलिपि या चाल विधियाँ बनाते हैं - जो कि अभिव्यंजक और समझने योग्य है

यह एक उत्तर नहीं है, लेकिन मुझे आशा है कि आप इसे पढ़ते समय एक पाएंगे।


0

मैं इस बात की सराहना करता हूं कि बच्चे के माता-पिता से संबंध होने के कारण इसकी डाउनसाइड्स जैसा कि ऊपर उल्लेख किया गया है।

हालांकि कई परिदृश्यों के लिए घटनाओं और अन्य "डिस्कनेक्टेड" यांत्रिकी के साथ कार्यपट्ट भी अपनी खुद की जटिलताएं और कोड की अतिरिक्त लाइनें लाते हैं।

उदाहरण के लिए, चाइल्ड की ओर से एक घटना को प्राप्त करने के लिए यह माता-पिता दोनों एक साथ मिलकर ढीले कपलिंग फैशन में बांधेंगे।

शायद कई परिदृश्यों के लिए यह सभी डेवलपर्स के लिए स्पष्ट है कि चाइल्ड.पैरेंट संपत्ति का क्या मतलब है। अधिकांश प्रणालियों के लिए मैंने इस पर काम किया है, बस ठीक काम किया है। इंजीनियरिंग समय लेने वाली हो सकती है और…। भ्रामक!

एक पालक है। आटचचाइल्ड () विधि जो बच्चे को उसके माता-पिता को बांधने के लिए आवश्यक सभी कार्य करती है। हर कोई स्पष्ट है कि इसका क्या मतलब है "

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.