CodeGym /Java Blog /अनियमित /एडॉप्टर डिज़ाइन पैटर्न किन समस्याओं को हल करता है?
John Squirrels
स्तर 41
San Francisco

एडॉप्टर डिज़ाइन पैटर्न किन समस्याओं को हल करता है?

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

समस्या के बारे में अधिक

सबसे पहले, हम पुरानी प्रणाली के व्यवहार का अनुकरण करेंगे। मान लीजिए कि यह काम या स्कूल में देर से आने का बहाना बनाता है। ऐसा करने के लिए, इसका एक Excuseइंटरफ़ेस है जिसमें generateExcuse(), likeExcuse()और dislikeExcuse()विधियाँ हैं।

public interface Excuse {
   String generateExcuse();
   void likeExcuse(String excuse);
   void dislikeExcuse(String excuse);
}
वर्ग WorkExcuseइस इंटरफ़ेस को लागू करता है:

public class WorkExcuse implements Excuse {
   private String[] excuses = {"in an incredible confluence of circumstances, I ran out of hot water and had to wait until sunlight, focused using a magnifying glass, heated a mug of water so that I could wash.",
   "the artificial intelligence in my alarm clock failed me, waking me up an hour earlier than normal. Because it is winter, I thought it was still nighttime and I fell back asleep. Everything after that is a bit hazy.",
   "my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia."};
   private String [] apologies = {"This will not happen again, of course. I'm very sorry.", "I apologize for my unprofessional behavior.", "There is no excuse for my actions. I am not worthy of this position."};

   @Override
   public String generateExcuse() { // Randomly select an excuse from the array
       String result = "I was late today because " + excuses[(int) Math.round(Math.random() + 1)] + "\\n" +
               apologies[(int) Math.round(Math.random() + 1)];
       return result;
   }

   @Override
   public void likeExcuse(String excuse) {
       // Duplicate the element in the array so that its chances of being chosen are higher
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Remove the item from the array
   }
}
आइए हमारे उदाहरण का परीक्षण करें:

Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
आउटपुट:

"I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
I apologize for my unprofessional behavior.
अब कल्पना करें कि आपने एक बहाना बनाने वाली सेवा शुरू की है, आँकड़े एकत्र किए हैं, और देखा है कि आपके अधिकांश उपयोगकर्ता विश्वविद्यालय के छात्र हैं। इस समूह की बेहतर सेवा करने के लिए, आपने एक अन्य डेवलपर से एक ऐसी प्रणाली बनाने के लिए कहा जो विशेष रूप से विश्वविद्यालय के छात्रों के लिए बहाने बनाती है। विकास दल ने बाजार अनुसंधान किया, बहाने बनाए, कुछ कृत्रिम बुद्धिमत्ता को जोड़ा, और ट्रैफिक रिपोर्ट, मौसम रिपोर्ट आदि के साथ सेवा को एकीकृत किया। अब आपके पास विश्वविद्यालय के छात्रों के बहाने बनाने के लिए एक पुस्तकालय है, लेकिन इसका एक अलग इंटरफ़ेस है: StudentExcuse.

public interface StudentExcuse {
   String generateExcuse();
   void dislikeExcuse(String excuse);
}
इस इंटरफ़ेस की दो विधियाँ हैं: generateExcuse, जो एक बहाना बनाता है, और dislikeExcuse, जो बहाने को भविष्य में फिर से प्रकट होने से रोकता है। तीसरे पक्ष के पुस्तकालय को संपादित नहीं किया जा सकता है, अर्थात आप इसका स्रोत कोड नहीं बदल सकते। अब हमारे पास दो वर्गों वाली एक प्रणाली है जो Excuseइंटरफ़ेस को लागू करती है, और एक पुस्तकालय जिसमें एक SuperStudentExcuseवर्ग है जो StudentExcuseइंटरफ़ेस को लागू करता है:

public class SuperStudentExcuse implements StudentExcuse {
   @Override
   public String generateExcuse() {
       // Logic for the new functionality
       return "An incredible excuse adapted to the current weather conditions, traffic jams, or delays in public transport schedules.";
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Adds the reason to a blacklist
   }
}
कोड बदला नहीं जा सकता। वर्तमान वर्ग पदानुक्रम इस तरह दिखता है: एडॉप्टर डिज़ाइन पैटर्न किन समस्याओं को हल करता है?  - 2सिस्टम का यह संस्करण केवल एक्सक्यूज़ इंटरफ़ेस के साथ काम करता है। आप कोड को दोबारा नहीं लिख सकते: एक बड़े एप्लिकेशन में, इस तरह के बदलाव करना एक लंबी प्रक्रिया बन सकती है या एप्लिकेशन के तर्क को तोड़ सकती है। हम एक आधार इंटरफ़ेस पेश कर सकते हैं और पदानुक्रम का विस्तार कर सकते हैं: एडॉप्टर डिज़ाइन पैटर्न किन समस्याओं को हल करता है?  - 3ऐसा करने के लिए, हमें Excuseइंटरफ़ेस का नाम बदलना होगा। लेकिन गंभीर अनुप्रयोगों में अतिरिक्त पदानुक्रम अवांछनीय है: एक सामान्य रूट तत्व को पेश करने से आर्किटेक्चर टूट जाता है। आपको एक मध्यवर्ती वर्ग लागू करना चाहिए जो हमें कम से कम नुकसान के साथ नई और पुरानी कार्यक्षमता दोनों का उपयोग करने देगा। संक्षेप में, आपको एक एडेप्टर की आवश्यकता है

एडेप्टर पैटर्न के पीछे सिद्धांत

एडेप्टर एक मध्यवर्ती वस्तु है जो एक वस्तु की विधि कॉल को दूसरे द्वारा समझने की अनुमति देता है। आइए हमारे उदाहरण के लिए एक एडेप्टर लागू करें और इसे कॉल करें Middleware। हमारे एडॉप्टर को एक ऐसे इंटरफेस को लागू करना चाहिए जो किसी एक ऑब्जेक्ट के साथ संगत हो। रहने दो Excuse। यह Middlewareपहली वस्तु के तरीकों को कॉल करने की अनुमति देता है। Middlewareकॉल प्राप्त करता है और उन्हें दूसरी वस्तु के अनुकूल तरीके से अग्रेषित करता है। यहां और विधियों Middlewareके साथ कार्यान्वयन है : generateExcusedislikeExcuse

public class Middleware implements Excuse { // 1. Middleware becomes compatible with WorkExcuse objects via the Excuse interface

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) { // 2. Get a reference to the object being adapted
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse(); // 3. The adapter implements an interface method
   }

    @Override
    public void dislikeExcuse(String excuse) {
        // The method first adds the excuse to the blacklist,
        // Then passes it to the dislikeExcuse method of the superStudentExcuse object.
    }
   // The likeExcuse method will appear later
}
परीक्षण (क्लाइंट कोड में):

public class Test {
   public static void main(String[] args) {
       Excuse excuse = new WorkExcuse(); // We create objects of the classes
       StudentExcuse newExcuse = new SuperStudentExcuse(); // that must be compatible.
       System.out.println("An ordinary excuse for an employee:");
       System.out.println(excuse.generateExcuse());
       System.out.println("\n");
       Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Wrap the new functionality in the adapter object
       System.out.println("Using new functionality with the adapter:");
       System.out.println(adaptedStudentExcuse.generateExcuse()); // The adapter calls the adapted method
   }
}
आउटपुट:

An ordinary excuse for an employee:
I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
There is no excuse for my actions. I am not worthy of this position. Using new functionality with the adapter:
वर्तमान मौसम की स्थिति, ट्रैफिक जाम, या सार्वजनिक परिवहन कार्यक्रम में देरी के लिए अनुकूलित एक अविश्वसनीय बहाना। विधि generateExcuseबिना किसी अतिरिक्त परिवर्तन के कॉल को किसी अन्य ऑब्जेक्ट पर भेजती है। विधि dislikeExcuseके लिए हमें पहले बहाने को ब्लैकलिस्ट करना पड़ता था। इंटरमीडिएट डेटा प्रोसेसिंग करने की क्षमता एक कारण है कि लोग एडॉप्टर पैटर्न को पसंद करते हैं। likeExcuseलेकिन उस विधि के बारे में क्या है जो Excuseइंटरफ़ेस का हिस्सा है लेकिन StudentExcuseइंटरफ़ेस का हिस्सा नहीं है? नई कार्यक्षमता इस कार्रवाई का समर्थन नहीं करती है। UnsupportedOperationExceptionइस स्थिति के लिए आविष्कार किया गया था । अनुरोधित ऑपरेशन समर्थित नहीं होने पर इसे फेंक दिया जाता है। आइए इसका इस्तेमाल करते हैं। इस प्रकार Middlewareवर्ग का नया कार्यान्वयन दिखता है:

public class Middleware implements Excuse {

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) {
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse();
   }

   @Override
   public void likeExcuse(String excuse) {
       throw new UnsupportedOperationException("The likeExcuse method is not supported by the new functionality");
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // The method accesses a database to fetch additional information,
       // and then passes it to the superStudentExcuse object's dislikeExcuse method.
   }
}
पहली नज़र में, यह समाधान बहुत अच्छा नहीं लगता, लेकिन कार्यक्षमता की नकल करने से स्थिति जटिल हो सकती है। यदि क्लाइंट ध्यान देता है, और एडॉप्टर अच्छी तरह से प्रलेखित है, तो ऐसा समाधान स्वीकार्य है।

एडेप्टर का उपयोग कब करें

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

  2. जब कई मौजूदा उपवर्गों को कुछ सामान्य कार्यक्षमता की आवश्यकता होती है। अतिरिक्त उपवर्ग बनाने के बजाय (जिससे कोड का दोहराव होगा), एडॉप्टर का उपयोग करना बेहतर है।

फायदे और नुकसान

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

एडेप्टर को मुखौटा या डेकोरेटर के साथ भ्रमित न करें

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

चरण-दर-चरण एल्गोरिथम

  1. सबसे पहले, सुनिश्चित करें कि आपको कोई समस्या है कि यह पैटर्न हल कर सकता है।

  2. क्लाइंट इंटरफ़ेस को परिभाषित करें जिसका उपयोग अप्रत्यक्ष रूप से असंगत वस्तुओं के साथ बातचीत करने के लिए किया जाएगा।

  3. एडॉप्टर क्लास को पिछले चरण में परिभाषित इंटरफ़ेस को इनहेरिट करें।

  4. एडॉप्टर क्लास में, एडेप्टी ऑब्जेक्ट के संदर्भ को स्टोर करने के लिए एक फील्ड बनाएं। यह संदर्भ कंस्ट्रक्टर को दिया जाता है।

  5. एडॉप्टर में सभी क्लाइंट इंटरफ़ेस विधियों को लागू करें। एक विधि हो सकती है:

    • बिना किसी बदलाव के कॉल पास करें

    • डेटा को संशोधित या पूरक करें, लक्ष्य विधि में कॉल की संख्या में वृद्धि/कमी करें, आदि।

    • अत्यधिक मामलों में, यदि कोई विशेष विधि असंगत रहती है, तो एक असमर्थितऑपरेशन अपवाद को फेंक दें। असमर्थित संचालन को सख्ती से प्रलेखित किया जाना चाहिए।

  6. यदि एप्लिकेशन क्लाइंट इंटरफ़ेस के माध्यम से केवल एडेप्टर वर्ग का उपयोग करता है (जैसा कि ऊपर के उदाहरण में है), तो एडेप्टर को भविष्य में दर्द रहित रूप से विस्तारित किया जा सकता है।

बेशक, यह डिज़ाइन पैटर्न सभी बीमारियों के लिए रामबाण नहीं है, लेकिन यह विभिन्न इंटरफेस वाली वस्तुओं के बीच असंगति की समस्या को सुरुचिपूर्ण ढंग से हल करने में आपकी मदद कर सकता है। एक डेवलपर जो बुनियादी पैटर्न जानता है, उन लोगों से कई कदम आगे है जो केवल एल्गोरिदम लिखना जानते हैं, क्योंकि गंभीर एप्लिकेशन बनाने के लिए डिज़ाइन पैटर्न की आवश्यकता होती है। कोड का पुन: उपयोग इतना कठिन नहीं है, और रखरखाव सुखद हो जाता है। यह सभी आज के लिए है! लेकिन हम जल्द ही विभिन्न डिज़ाइन पैटर्न के बारे में जानना जारी रखेंगे :)
टिप्पणियां
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION