"ढीली युग्मन क्या है?" कृपया उदाहरण दें


172

मैं "ढीली युग्मन" की अवधारणा को नहीं समझ सकता। मुझे लगता है कि यह मदद नहीं करता है कि "ढीला" शब्द का आमतौर पर नकारात्मक अर्थ होता है, इसलिए मैं हमेशा यह भूल जाता हूं कि ढीली युग्मन एक अच्छी बात है।

क्या कोई कृपया इस कोड को दर्शाने वाले "कोड" (या स्यूडोकोड) के बाद "पहले" और "कुछ" दिखाएगा?


मुझे यकीन नहीं है कि यह एक विशेष भाषा से तलाक कैसे हो सकता है क्योंकि अवधारणा का हिस्सा यह है कि कैसे कोड इकाइयों को एक-दूसरे से बहुत अधिक उलझने से बचाने के लिए कोई भाषा का उपयोग करता है। मैं यह भी ध्यान देता हूं कि कई उत्तर अवधारणा को समझने के लिए कोड का सहारा लेते हैं।
ओनोरियो कैटेनेशिया

11
पूरी तरह से असहमत, व्यावहारिकताओं को अलग-अलग भाषाओं में अलग-अलग रूप में चित्रित किया जा सकता है, और यह गतिशील बनाम संकलित भाषाओं में विशेष रूप से स्पष्ट है। लेकिन अवधारणा एक ही रास्ता है।
ओवेन

ढीला बनाम तंग और युग्मन बनाम Decoupling । साथ टैग करना हमेशा अच्छी बात नहीं है, कभी-कभी अच्छी / कभी-कभी अच्छी नहीं होती ... जैसा कि हमें अपनी खुद की स्वतंत्रता होनी चाहिए , इसलिए कक्षाएं करें।
bonCodigo

जवाबों:


180

खरीदारी की प्रक्रिया में वस्तुओं पर नज़र रखने के लिए और खरीदारी की प्रक्रिया के लिए ऑर्डर क्लास का उपयोग करने के लिए एक साधारण खरीदारी कार्ट एप्लिकेशन का उपयोग करें, जो कार्टकोन्ट्स क्लास का उपयोग करता है। गाड़ी में सामग्री के कुल मूल्य को निर्धारित करने के लिए आदेश की आवश्यकता है, यह ऐसा कर सकता है:

कसकर युग्मित उदाहरण:

public class CartEntry
{
    public float Price;
    public int Quantity;
}

public class CartContents
{
    public CartEntry[] items;
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        float cartTotal = 0;
        for (int i = 0; i < cart.items.Length; i++)
        {
            cartTotal += cart.items[i].Price * cart.items[i].Quantity;
        }
        cartTotal += cartTotal*salesTax;
        return cartTotal;
    }
}

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

अब यहाँ एक ही काम करने का थोड़ा बेहतर तरीका है:

कम युग्मित उदाहरण:

public class CartEntry
{
    public float Price;
    public int Quantity;

    public float GetLineItemTotal()
    {
        return Price * Quantity;
    }
}

public class CartContents
{
    public CartEntry[] items;

    public float GetCartItemsTotal()
    {
        float cartTotal = 0;
        foreach (CartEntry item in items)
        {
            cartTotal += item.GetLineItemTotal();
        }
        return cartTotal;
    }
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        return cart.GetCartItemsTotal() * (1.0f + salesTax);
    }
}

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


क्या आप निर्भरता इंजेक्शन (हालांकि निर्माता आदर्श होना चाहिए) के माध्यम से आगे डिकम्पलिंग शुरू करने वाले उत्तर का विस्तार कर सकते हैं?
BAD_SEED

4
@ बचाव, मुझे Orderकोई ज्ञान नहीं होने का कोई कारण नहीं दिखता Cart। लाइव शॉपिंग और फैक्टरशिप दो अलग-अलग संदर्भ हैं। जब ग्राहक भुगतान करने के लिए तैयार हो जाता है, तो आपके पास कार्टएंट्रीज़ को अनुवाद करने के लिए जिम्मेदार प्रक्रिया हो सकती है Order। इस तरह से Orderकक्षा को भी बिना किसी इंस्टैंस और उपयोग किया जाएगा Cart
प्लेक्स

@ कृपया आप मेरी टिप्पणी पर प्रतिक्रिया दे सकते हैं?
प्लेक्स

अच्छी तरह से और बस समझाया। मैं "..नोटिस कैसे ऑर्डरटोटल विधि (और इस तरह ऑर्डर क्लास) कार्टक्रॉन्टेंट्स और कार्टइंट्री कक्षाओं के कार्यान्वयन विवरण पर निर्भर करता है .." को देखने के लिए शुरू किया
okey_on

यह उदाहरण स्पष्ट रूप से प्रस्तुत किया गया है। हालांकि इन दिनों में, अधिक से अधिक आर्किटेक्ट इस बात से सहमत हैं कि यह अत्यधिक वस्तु-उन्मुख शैली खराब अभ्यास है। के "कार्यान्वयन" जानकारी को छिपाए का कोई मतलब नहीं है CartEntryऔर CartContents। चूंकि ये पूरी तरह से स्पष्ट अर्थ हैं, इसलिए उन्हें केवल मृत डेटा के रूप में चित्रित किया जाना चाहिए। डेटाबेस के संदर्भ में, यहां जो कुछ भी आवश्यक है वह एक मेज हैCREATE TABLE entry (price INTEGER, quantity INTEGER)
जो

160

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

वही सॉफ्टवेयर विकास के लिए जाता है: विस्तार और प्रतिस्थापन को सुविधाजनक बनाने के लिए (और अलग-अलग हिस्सों को समझने में आसान बनाने के लिए) यह आमतौर पर (बहुत) बेहतर होता है। लेकिन, बहुत कम ही, विशेष परिस्थितियों में तंग युग्मन फायदेमंद हो सकता है क्योंकि कई मॉड्यूलों का तंग एकीकरण बेहतर अनुकूलन की अनुमति देता है।


क्या ढीली या तंग युग्मन अच्छा है? ढीले युग्मन या तंग युग्मन को लागू करने का निर्णय कैसे करें?
श्रीकांत करुमनघाट

2
इस महान उदाहरण के लिए धन्यवाद। मैं अन्य उत्तरों पर बहुत समय बिताता था, लेकिन इस तरह के लायक नहीं था
अलामिन

1
श्रीकांत करुमनघाट, क्या आप सिर्फ एक बैटरी के लिए कम पैसा खर्च करेंगे और फिर से काम करने वाले आईपॉड होंगे या आप पूरे आईपॉड के लिए बहुत सारे पैसे खर्च करना पसंद करेंगे?
कोशेरा

1
@ श्रीकांतकर्मनघाट आमतौर पर ढीली कपलिंग बेहतर होती है क्योंकि यह प्रतिरूपकता को बढ़ावा देती है और इस तरह से कोड को बनाए रखना आसान हो जाता है। यदि आप अपनी कक्षाओं / पुस्तकालयों / कोड को कसकर जोड़ते हैं, तो एक वर्ग में आपके द्वारा किए गए किसी भी छोटे परिवर्तन को उन सभी वर्गों में लागू करना होगा जो इसका उपयोग करते हैं।
केनी वर्डेन

56

मैं एक उदाहरण के रूप में जावा का उपयोग करूँगा। मान लीजिए कि हमारे पास एक वर्ग है जो इस तरह दिखता है:

public class ABC
{
   public void doDiskAccess() {...}
}

जब मैं कक्षा को बुलाऊंगा, तो मुझे ऐसा कुछ करने की आवश्यकता होगी:

ABC abc = new ABC();

abc. doDiskAccess();

अब तक सब ठीक है। अब कहते हैं कि मेरे पास एक और वर्ग है जो इस तरह दिखता है:

public class XYZ
{
   public void doNetworkAccess() {...}
}

यह एबीसी के समान ही दिखता है, लेकिन मान लें कि यह डिस्क पर नेटवर्क के बजाय काम करता है। तो अब इस तरह से एक कार्यक्रम लिखते हैं:

if(config.isNetwork()) new XYZ().doNetworkAccess();
else new ABC().doDiskAccess();

यह काम करता है, लेकिन यह एक छोटा सा है। मैं इसे इस तरह के एक अंतरफलक के साथ सरल बना सकता है:

public interface Runnable
{
    public void run();
}

public class ABC implements Runnable
{
   public void run() {...}
}

public class XYZ implements Runnable
{
   public void run() {...}
}

अब मेरा कोड इस तरह दिख सकता है:

Runnable obj = config.isNetwork() ? new XYZ() : new ABC();

obj.run();

देखें कि कितना क्लीनर और सरल है यह समझने के लिए? हम ढीले युग्मन के पहले मूल सिद्धांत को समझ गए हैं: अमूर्तता। यहां से कुंजी यह सुनिश्चित करना है कि एबीसी और एक्सवाईजेड कक्षाओं के किसी भी तरीके या चर पर निर्भर नहीं करते हैं जो उन्हें कहते हैं। यह ABC और XYZ को पूरी तरह से स्वतंत्र एपीआई बनाने की अनुमति देता है। या दूसरे शब्दों में, वे मूल वर्गों से "डिकॉउल्ड" या "शिथिल युग्मित" हैं।

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


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

ये रन * और डू * नाम की विधियाँ मेरे लिए एक बड़ी कूट गंध हैं। आप IHandleStuff या IFrobnicateThings का उपयोग करने के लिए इसे भी रिफ्लेक्टर कर सकते हैं। Runnable दूर है, इस मामले में बहुत सामान्य शब्द है।
वेज

8
ओवेन, बेबी मेरे दोस्त को कदम। यदि वह युग्मन को नहीं समझता है, तो वह यह कैसे समझने वाला है कि कारखाना पैटर्न उसे क्या खरीदता है? यह कोड उदाहरण उसे सही रास्ते पर लाता है। आशय यह है कि वह समस्या को बेहतर ढंग से समझेगा और महसूस करेगा कि वस्तुओं के निर्माण को कैसे अमूर्त किया जाए।
64Bitbus

6
इस अधिक पठनीय नहीं होगा अगर एबीसी और XYZ की तरह कुछ का नाम दिया गया DiskAccessorऔर NetworkAccessor? आई
डननो

क्या यह फैक्टरी डिजाइन पैटर्न का भी उपयोग करता है? क्योंकि हम जरूरत के आधार पर नए XYZ या ABC ऑब्जेक्ट्स बना रहे हैं।
मुनमुनब

37

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

ढीली युग्मन का सीधा सा मतलब है कि अलग-अलग डिजाइन तत्वों का निर्माण किया जाना चाहिए ताकि अनावश्यक जानकारी की मात्रा के बारे में उन्हें अन्य डिजाइन तत्वों के बारे में जानने की आवश्यकता हो।

उच्च सामंजस्य "तंग युग्मन" की तरह है, लेकिन उच्च सामंजस्य एक ऐसी स्थिति है जहां डिजाइन तत्वों को वास्तव में एक दूसरे के बारे में जानने की आवश्यकता होती है ताकि वे एक साथ सफाई और सुरुचिपूर्ण ढंग से काम करें।

मुद्दा यह है कि, कुछ डिज़ाइन तत्वों को अन्य डिज़ाइन तत्वों के बारे में विवरण जानना चाहिए, इसलिए उन्हें इस तरह से डिज़ाइन किया जाना चाहिए, न कि गलती से। अन्य डिज़ाइन तत्वों को अन्य डिज़ाइन तत्वों के बारे में विवरण नहीं पता होना चाहिए, इसलिए उन्हें बेतरतीब ढंग से बजाय, इस तरह से डिज़ाइन किया जाना चाहिए।

इसे लागू करना पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है :)।


33

कसकर युग्मित कोड एक ठोस कार्यान्वयन पर निर्भर करता है। अगर मुझे अपने कोड में तार की सूची चाहिए और मैं इसे इस तरह से घोषित करता हूं (जावा में)

ArrayList<String> myList = new ArrayList<String>();

तो मैं ArrayList कार्यान्वयन पर निर्भर हूँ।

अगर मैं इसे कपल कोड में बदलना चाहता हूं, तो मैं अपने संदर्भ को एक इंटरफ़ेस (या अन्य सार) प्रकार बनाता हूं।

List<String> myList = new ArrayList<String>();

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

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


यह वास्तव में "युग्मन" से संबंधित है । कुछ अच्छे उत्तरों के लिए stackoverflow.com/questions/39946/coupling-and-cohesion देखें ।
रोजेरियो

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

@Bill: लिंक के लिए धन्यवाद, लेकिन यह लेख मुझे पूरी तरह से फर्जी लगता है। यह एक अन्य डोमेन (संगठनात्मक व्यवहार) से विचारों को "पुनर्व्याख्या" करने के लिए प्रकट होता है, "ढीली युग्मन" की परिभाषा देता है जो लैरी कॉन्सटेंटाइन द्वारा मूल सॉफ़्टवेयर-विशिष्ट परिभाषा का विरोध करता है: en.wikipedia.org/wiki/Canpling_(computer_science)
रोजेरियो

@ रोगेरियो: कांस्टेंटाइन का पेपर 1974 में लिखा गया था। यह संभावना है कि पिछले 36 वर्षों में बहुत अधिक पुनर्संरचना हुई है, लेकिन मुझे नहीं लगता कि विकिपीडिया लेख इसका स्रोत है। उदाहरण के लिए, डिपेंडेंसी इंजेक्शन जैसे पैटर्न मेरे जवाब में बताए अनुसार युग्मन को ढीला करने के लिए इंटरफेस पर निर्भर करते हैं।
छिपकली

2
@ बिल: निश्चित रूप से, संरचित डिजाइन पर कॉन्स्टेंटाइन का काम पुराना सामान है, लेकिन मैं इसे अमान्य या मौलिक रूप से पुनर्व्याख्या करने के किसी भी कारण को देखने में विफल हूं। सामंजस्य और युग्मन की मूल अवधारणाएं ऑब्जेक्ट ओरिएंटेड डिज़ाइन के मूल में हैं, बस विरासत और बहुरूपता के रूप में। DI (एक बेहतर लेख है martinfowler.com/articles/injection.html ) केवल प्लग-इन के बाहरी कॉन्फ़िगरेशन के लिए एक तकनीक है (कॉन्फ़िगरेशन कोड के माध्यम से रनटाइम पर चयनित कार्यान्वयन के साथ सार इंटरफेस); इस तरह की एक और तकनीक सेवा लोकेटर पैटर्न है। डि और युग्मन स्वतंत्र अवधारणाएं हैं।
रोजेरियो

27

यहाँ जवाबों के बीच अंतर की डिग्री से पता चलता है कि इसे समझ पाना एक कठिन अवधारणा क्यों होगी लेकिन इसे केवल उसी तरह से रखा जा सकता है जैसे मैं इसका वर्णन कर सकता हूं:

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

ग # या जावा आदि जैसी गैर-गतिशील भाषाओं के साथ, हम इसे इंटरफेस के माध्यम से पूरा करते हैं। तो हम कहते हैं कि हम निम्नलिखित इंटरफ़ेस है:

public ICatcher
{
   public void Catch();
}

और अब हम कहते हैं कि हमारे पास निम्न वर्ग हैं:

public CatcherA : ICatcher
{
   public void Catch()
   {
      console.writeline("You Caught it");
   }

}
public CatcherB : ICatcher
{
   public void Catch()
   {
      console.writeline("Your brother Caught it");
   }

}

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

public CatchService
{
   private CatcherA catcher = new CatcherA();

   public void CatchService()
   {
      catcher.Catch();
   }

}

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

अब एक और विकल्प लेते हैं, जिसे निर्भरता इंजेक्शन कहा जाता है:

public CatchService
{
   private ICatcher catcher;

   public void CatchService(ICatcher catcher)
   {
      this.catcher = catcher;
      catcher.Catch();
   }
}

तो कैल्स जो कि कैचअप सेवा को बढ़ावा देता है, वह निम्न कार्य कर सकता है:

CatchService catchService = new CatchService(new CatcherA());

या

CatchService catchService = new CatchService(new CatcherB());

इसका मतलब यह है कि कैच सर्विस को कैचर या कैचरबी दोनों में से किसी को भी कसकर नहीं जोड़ा जाता है।

इस तरह की शिथिल युग्मन सेवाओं के लिए कई अन्य स्ट्रैटिजी हैं जैसे कि एक IoC ढांचे का उपयोग आदि।


1
मुझे यह उदाहरण अन्य लोगों की तुलना में बेहतर लगता है, क्योंकि दिन-प्रतिदिन के कारोबार में इस तरह की बात होती है। अगर क्लास पर्सन चलता है, क्लास कैट चलता है, क्लास डॉग रन करता है, तो यह उन सभी वर्गों को चलाने के लिए एक बड़ा कार्यक्रम होगा। लेकिन रन नामक एक इंटरफ़ेस का उपयोग करना, जहां प्रत्येक वर्ग एक ही काम करता है, आपके कार्यक्रम को अधिक लचीला और प्रबंधनीय बनाता है। :)
sksallaj

वास्तव में अच्छी तरह से समझाया सर, बस आखिरी उदाहरण में स्पष्ट करने के लिए आपने इसे निर्भरता इंजेक्शन के साथ किया था, और पहला उदाहरण भी शिथिल युग्मित है?
अली साजिद

वाह, पुराने उत्तर पर टिप्पणी :)। तो इसका जवाब है नहीं, पहले उदाहरण में कैचर पर एक कठिन निर्भरता है, इसलिए वे दृढ़ता से युग्मित हैं
ओवेन

23

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


1
तो, "शिथिल युग्मित" वास्तव में कम निर्भरता का मतलब है? क्या मैं सही हूँ?
user314362

4
यह वास्तव में निर्भरता की कुल संख्या से संबंधित नहीं है जो एक विशेष वर्ग के पास है। युग्मन (चुस्त या ढीला) वास्तव में दो वर्गों के बीच संबंधों की एक संपत्ति है। तो आपके पास एक वर्ग हो सकता है जो शिथिल रूप से 100 अन्य वर्गों के लिए है, या एक अन्य वर्ग जो कसकर केवल 2 अन्य वर्गों (उदाहरण के लिए) के लिए युग्मित है।
मुसैनीस

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

@Rogerio: यह शायद सबसे अच्छा उदाहरण नहीं है। मुझे 64BitBobखुद ही बेहतर जवाब पसंद है ।
मुसईनेसिस

12

परिभाषा

अनिवार्य रूप से, युग्मन यह है कि किसी दिए गए ऑब्जेक्ट या ऑब्जेक्ट का सेट किसी अन्य ऑब्जेक्ट या ऑब्जेक्ट के किसी अन्य सेट पर निर्भर करता है ताकि उसके कार्य को पूरा किया जा सके।

उच्च युग्मन

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

ढीला युग्मन

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


7

यह एक बहुत सामान्य अवधारणा है, इसलिए कोड उदाहरण पूरी तस्वीर देने वाले नहीं हैं।

यहाँ काम करने वाले एक व्यक्ति ने मुझसे कहा, "पैटर्न फ्रैक्टल्स की तरह होते हैं, आप उन्हें तब देख सकते हैं जब आप वास्तव में पास में ज़ूम करते हैं, और जब आप आर्किटेक्चर स्तर पर ज़ूम आउट करते हैं।"

संक्षिप्त विकिपीडिया पृष्ठ पढ़ना आपको इस सामान्यता का एहसास दिला सकता है:

http://en.wikipedia.org/wiki/Loose_coupling

जहाँ तक एक विशिष्ट कोड का उदाहरण है ...

यहाँ मैंने हाल ही में Microsoft.Practices.CompositeUI सामानों के साथ काम किया एक ढीला युग्मन है।

    [ServiceDependency]
    public ICustomizableGridService CustomizableGridService
    {
        protected get { return _customizableGridService; }
        set { _customizableGridService = value; }
    }

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

यदि यह स्पष्ट नहीं है, तो आप यहां अधिक विस्तृत विवरण पढ़ सकते हैं:

http://en.wikipedia.org/wiki/Dependency_injection

कल्पना कीजिए कि ABCCustomizableGridService है imlpementation मैं यहाँ हुक करने का इरादा रखता हूं।

यदि मैं चुनता हूं, तो मैं इसे बाहर निकाल सकता हूं और इसे XYZCustomizableGridService, या StubCustomizableGridService के साथ प्रतिस्थापित कर सकता हूं और इस निर्भरता के साथ वर्ग में कोई बदलाव नहीं कर सकता।

अगर मैंने ABCCustomizableGridService को सीधे संदर्भित किया था, तो मुझे किसी अन्य सेवा कार्यान्वयन में स्वैप करने के लिए उस / उन संदर्भों में परिवर्तन करने की आवश्यकता होगी।


6

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

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

कुछ उदाहरण:

  • आवेदन एक पुस्तकालय पर निर्भर करता है। टाइट कपलिंग के तहत ऐप लिब के नए संस्करणों पर ब्रेक लगाता है। Google "DLL नर्क" के लिए।

  • क्लाइंट ऐप एक सर्वर से डेटा पढ़ता है। तंग युग्मन के तहत, सर्वर में परिवर्तन के लिए क्लाइंट पक्ष पर सुधार की आवश्यकता होती है।

  • ऑब्जेक्ट-ओरिएंटेड पदानुक्रम में दो वर्ग परस्पर क्रिया करते हैं। तंग युग्मन के तहत, एक वर्ग में परिवर्तन के लिए दूसरे वर्ग को मिलान के लिए अद्यतन करने की आवश्यकता होती है।

  • एकाधिक कमांड-लाइन उपकरण एक पाइप में संचार करते हैं। यदि उन्हें कसकर युग्मित किया जाता है, तो एक कमांड-लाइन टूल के संस्करण में परिवर्तन से उन टूल्स में त्रुटियां होंगी जो इसका आउटपुट पढ़ते हैं।


5

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

ढीले-ढाले वर्ग इसके विपरीत हैं कि एक-दूसरे पर उनकी निर्भरता न्यूनतम रखी जाती है और इसके बजाय वे एक-दूसरे के अच्छी तरह से परिभाषित सार्वजनिक इंटरफेस पर निर्भर होते हैं।

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

संदर्भ: https://megocode3.wordpress.com/2008/02/14/coupling-and-cohesion/


4

जब वे एक-दूसरे के ठोस कार्यान्वयन पर निर्भर होते हैं, तो दो घटक युग्मित होते हैं।

मान लीजिए कि मेरी कक्षा में एक विधि में यह कोड कहीं है:

this.some_object = new SomeObject();

अब मेरा वर्ग SomeObject पर निर्भर करता है, और वे अत्यधिक युग्मित हैं। दूसरी ओर, मान लें कि मेरे पास एक विधि है InjectSomeObject:

void InjectSomeObject(ISomeObject so) { // note we require an interface, not concrete implementation
  this.some_object = so;
}

तब पहला उदाहरण बस इंजेक्टेड SomeObject का उपयोग कर सकता है। यह परीक्षण के दौरान उपयोगी है। सामान्य ऑपरेशन के साथ, आप हल्के, नकली कार्यान्वयन से गुजरने वाले परीक्षणों के लिए भारी, डेटाबेस का उपयोग, नेटवर्क का उपयोग करने वाली कक्षाएं आदि का उपयोग कर सकते हैं। कसकर युग्मित कोड के साथ आप ऐसा नहीं कर सकते।

आप निर्भरता इंजेक्शन कंटेनरों का उपयोग करके इस काम के कुछ हिस्सों को आसान बना सकते हैं। आप DI के बारे में विकिपीडिया: http://en.wikipedia.org/wiki/D dependency_injection पर अधिक पढ़ सकते हैं ।

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


3

FormA और FormB के साथ एक विंडोज ऐप पर विचार करें। FormA प्राथमिक रूप है और यह FormB प्रदर्शित करता है। अपने माता-पिता को डेटा वापस देने के लिए फॉर्मब की आवश्यकता की कल्पना करें।

यदि आपने ऐसा किया है:

class FormA 
{
    FormB fb = new FormB( this );

    ...
    fb.Show();
}

class FormB 
{
    FormA parent;

    public FormB( FormA parent )
    {
        this.parent = parent;
    }     
}

FormB कसकर FormA से जुड़ा है। FormB का कोई अन्य माता-पिता नहीं हो सकता है जो कि FormA से भिन्न हो।

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

आरपी


3

कंप्यूटर विज्ञान में "ढीले युग्मन" का एक और अर्थ है कि किसी और ने यहां के बारे में पोस्ट नहीं किया है, इसलिए ... यहाँ जाता है - उम्मीद है कि आप मुझे कुछ वोट देंगे ताकि यह ढेर के नीचे खो न जाए! मेरे प्रश्न का उत्तर प्रश्न के किसी भी व्यापक उत्तर में है ... बुद्धि के लिए:

"लूज़ कपलिंग" शब्द पहली बार एक मल्टी-सीपीयू कॉन्फ़िगरेशन में सीपीयू आर्किटेक्चर के बारे में विशेषण के रूप में इस्तेमाल होने वाले शब्द के रूप में दर्ज किया गया था। इसका समकक्ष शब्द "तंग युग्मन" है। ढीला युग्मन तब होता है जब सीपीयू कई संसाधनों को साझा नहीं करते हैं और जब वे करते हैं तो टाइट युग्मन होता है।

शब्द "सिस्टम" यहां भ्रमित हो सकता है इसलिए कृपया स्थिति को ध्यान से देखें।

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

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

पहला, चूंकि यह सवाल था कि लूज़ली कपल्ड सिस्टम के कुछ उदाहरण क्या हैं:

  • VaxClusters
  • लिनक्स क्लस्टर

इसके विपरीत, कुछ कसकर युग्मित उदाहरण:

  • सेमीमेट्रिक-मल्टी-प्रोसेसिंग (एसएमपी) ऑपरेटिंग सिस्टम - जैसे फेडोरा 9
  • बहु थ्रेडेड सीपीयू
  • मल्टी-कोर सीपीयू

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


3

सरल भाषा में, शिथिल युग्मित का अर्थ है कि यह होने वाली अन्य घटना पर निर्भर नहीं करता है। यह स्वतंत्र रूप से निष्पादित होता है।


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

हाँ, बहुत उपयोगी नहीं
brgs

2

कुछ लंबे जवाब यहाँ। सिद्धांत बहुत सरल है। मैं विकिपीडिया से प्रारंभिक विवरण प्रस्तुत करता हूं :

"ढीली युग्मन दो या दो से अधिक प्रणालियों या संगठनों के बीच एक लचीला संबंध का वर्णन करता है जिसमें कुछ प्रकार के विनिमय संबंध होते हैं।

लेनदेन का प्रत्येक छोर अपनी आवश्यकताओं को स्पष्ट करता है और दूसरे छोर के बारे में कुछ धारणाएं बनाता है। "


1
अगर यह इतना आसान था, तो हम इस चर्चा नहीं करेंगे।
brgs

2

मैं कोड युग्मन का एक बहुत ही सरल परीक्षण प्रस्तावित करता हूं :

  1. कोड A का टुकड़ा A कोड के टुकड़ा B से कसकर जोड़ा जाता है यदि कोई टुकड़ा B के लिए कोई भी संभावित संशोधन मौजूद है जो सहीता रखने के लिए टुकड़ा A में परिवर्तन को मजबूर करेगा।

  2. कोड A का टुकड़ा A कोड के टुकड़ा B से कसकर युग्मित नहीं है यदि कोई टुकड़ा B के लिए कोई संभावित संशोधन नहीं है जो कि टुकड़ा A के लिए आवश्यक परिवर्तन कर देगा।

इससे आपको यह सत्यापित करने में मदद मिलेगी कि आपके कोड के टुकड़ों के बीच कितना युग्मन है। उस तर्क के लिए इस ब्लॉग पोस्ट को देखें: http://marekdec.wordpress.com/2012/11/14/loose-coupling-tight-coupling-decoupling-what-is-that-all-about/


2

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

--- A.java ---

package interface_package.loose_coupling;

public class A {

void display(InterfaceClass obji)
{
    obji.display();
    System.out.println(obji.getVar());
}
}

--- B.java ---

package interface_package.loose_coupling;

public class B implements InterfaceClass{

private String var="variable Interface";

public String getVar() {
    return var;
}

public void setVar(String var) {
    this.var = var;
}

@Override
public void display() {
    // TODO Auto-generated method stub
    System.out.println("Display Method Called");
}
}

--- InterfaceClass ---

package interface_package.loose_coupling;

public interface InterfaceClass {

void display();
String getVar();
}

--- MainClass ---

package interface_package.loose_coupling;

public class MainClass {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    A obja=new A();
    B objb=new B();
    obja.display(objb);     //Calling display of A class with object of B class 

}
}

स्पष्टीकरण:

उपरोक्त उदाहरण में, हमारे पास दो वर्ग ए और बी हैं

क्लास बी लागू होता है इंटरफ़ेस अर्थात इंटरफ़ेसक्लास।

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

क्लास ए में हमारे पास प्रदर्शन विधि है जो क्लास के ऑब्जेक्ट को छोड़कर कर सकती है जो इंटरफ़ेसक्लास को लागू करती है (हमारे मामले में यह बी क्लास है)। और कक्षा A के उस ऑब्जेक्ट मेथड पर कॉलिंग डिस्प्ले () और क्लास B का getVar () है

मेनक्लास में हमने क्लास ए और बी की वस्तु बनाई है और बी क्लास की वस्तु यानी ओब्जेक्ट को पास करके ए की कॉलिंग डिस्प्ले विधि। ए की प्रदर्शन विधि को बी क्लास की वस्तु के साथ बुलाया जाएगा।

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

रेफरी: http://p3lang.com/2013/06/loose-coupling-example-use-interface/


0

आप "ढीली युग्मन" की सामान्य अवधारणा के बारे में अधिक पढ़ सकते हैं ।

संक्षेप में, यह दो वर्गों के बीच एक संबंध का वर्णन है, जहां प्रत्येक वर्ग दूसरे के बारे में बहुत कम जानता है और प्रत्येक वर्ग संभवतः ठीक काम करना जारी रख सकता है चाहे दूसरा मौजूद हो या नहीं और दूसरे के विशेष कार्यान्वयन पर निर्भरता के बिना कक्षा।


-8

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

आशा है कि कुछ हद तक उपयोगी है।


1
मैं देख रहा हूं कि आप क्या कर रहे हैं, लेकिन फिर भी यह समझाने का बहुत अच्छा तरीका नहीं है कि कसकर युग्मित है जब दो 'चीजें' एक दूसरे पर निर्भर होती हैं, तो दो युग्मित चीजों की तुलना में जब दो 'चीजें' स्वतंत्र रूप से मौजूद होती हैं - जहां एक चीज हो सकती है अन्य 'चीज़' में बदलाव के बिना बदल दिया जा सकता है ...
ब्रायन रेहबिन

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

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