डेकोरेटर पैटर्न

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

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

यह किन समस्याओं का समाधान कर सकता है?

 * कार्यावधि में गतिशील रूप से किसी वस्तु में जिम्मेदारियों को जोड़ा जाना चाहिए (और उससे हटा दिया जाना चाहिए)।
 * कार्यक्षमता बढ़ाने के लिए उपवर्गीकरण का एक लचीला विकल्प प्रदान किया जाना चाहिए।

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

यह किस समाधान का वर्णन करता है?
वस्तुओं कों परिभाषित करें
 * सभी अनुरोधों को अग्रेषित करके विस्तारित (सजाए गए) ऑब्जेक्ट के अंतराफलक को पारदर्शी रूप से प्रायुक्त करें
 * अनुरोध अग्रेषित करने से पहले/बाद में अतिरिक्त कार्यक्षमता निष्पादित करें।

यह कार्यावधि पर गतिशील रूप से ऑब्जेक्ट की कार्यक्षमता बढ़ाने के लिए विभिन्न  वस्तुओं के साथ काम करने की अनुमति देता है। नीचे यूएमएल वर्ग और अनुक्रम आरेख भी देखें।

विचार
डेकोरेटर पैटर्न का उपयोग किसी निश्चित वस्तु की कार्यक्षमता को स्थिर रूप से या कुछ स्तिथियों में रन-टाइम पर उसी वर्ग के अन्य उदाहरणों से स्वतंत्र रूप से विस्तारित (सजाने) के लिए किया जा सकता है, परन्तु डिजाइन समय पर कुछ आधारभूत कार्य किया जाता है। यह एक नया डेकोरेटर वर्ग डिजाइन करके प्राप्त किया जाता है जो मूल वर्ग को लपेटता है। यह रैपर पैटर्न के निम्नलिखित अनुक्रम द्वारा प्राप्त की जा सकती है:
 * 1) डेकोरेटर वर्ग में मूल घटक वर्ग को उपवर्गित करें (यूएमएल आरेख देखें);
 * 2) डेकोरेटर वर्ग में, एक घटक सूचक को एक क्षेत्र के रूप में जोड़ें;
 * 3) डेकोरेटर वर्ग में, घटक सूचक को हस्ताक्षर करने के लिए डेकोरेटर निर्माता को एक घटक पास करें;
 * 4) डेकोरेटर वर्ग में, घटक सूचक के लिए सभी घटक विधियों को अग्रेषित करें; और
 * 5) कंक्रीटडेकोरेटर वर्ग में, किसी भी घटक विधि को अधिभावी करें जिसके व्यवहार को संशोधित करने की आवश्यकता है।

इस पैटर्न को डिज़ाइन किया गया है जिससे ओवरराइड किए गए विधियों में एक नई कार्यक्षमता जोड़कर हर बार कई सज्जाकारों को एक-दूसरे के ऊपर रखा जा सकता हैं।

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

सजावट की विशेषताएं (जैसे, विधियाँ, गुण, या अन्य सदस्य) सामान्यतः एक इंटरफ़ेस, mixin (a.k.a. Trait_ (कंप्यूटर_प्रोग्रामिंग)) या वर्ग वंशानुक्रम द्वारा परिभाषित की जाती हैं, जो डेकोरेटर और सजी हुई वस्तु द्वारा साझा की जाती हैं। पिछले उदाहरण में, वर्ग घटक को कंक्रीटघटक और डेकोरेटर से उपवर्ग दोनों द्वारा विरासत में मिला है।

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

कार्यक्षमता बढ़ाने के कई स्वतंत्र विधि होने पर यह अंतर सबसे महत्वपूर्ण हो जाता है। कुछ वस्तु-उन्मुख प्रोग्रामिंग भाषा में, कक्षाएं रनटाइम पर नहीं बनाई जा सकती हैं, और सामान्यतः यह अनुमान लगाना संभव नहीं है कि डिज़ाइन समय पर एक्सटेंशन के कौन से संयोजन की आवश्यकता होगी। इसका भरोसा यह होगा कि हर संभव संयोजन के लिए एक नया वर्ग बनाना होगा। इसके विपरीत, सजावटी वस्तुएँ हैं, जो रनटाइम पर बनाई जाती हैं, और इन्हें प्रति-उपयोग के आधार पर जोड़ा जा सकता है। जावा प्लेटफॉर्म, मानक संस्करण java.io और .NET फ्रेमवर्क दोनों के I/O स्ट्रीम कार्यान्वयन में डेकोरेटर पैटर्न सम्मिलित है।

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

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

पिछले उदाहरण में, सिंपलविंडो और विंडोडेकोरेटर वर्ग विंडो इंटरफ़ेस को प्रायुक्त करते हैं, जो ड्रॉ विधि और गेटडिस्क्रिप्शन  विधि को परिभाषित करता है, जो विंडो नियंत्रण को सजाने के लिए इस परिदृश्य में आवश्यक हैं।

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

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

फ्लाईवेट वस्तु्स में उपयोग
फ्लाईवेट पैटर्न में सजावट का भी अधिकांश उपयोग किया जाता है। फ्लाईवेट ऑब्जेक्ट्स को दो घटकों में विभाजित किया गया है: एक अपरिवर्तनीय घटक जो सभी फ्लाईवेट ऑब्जेक्ट्स और एक वेरिएंट, सजाए गए घटक के बीच साझा किया जाता है जो आंशिक रूप से साझा किया जा सकता है या पूरी प्रकार से साझा नहीं किया जा सकता है। फ्लाईवेट ऑब्जेक्ट के इस विभाजन का उद्देश्य स्मृति खपत को कम करना है। सज्जाकार सामान्यतः कैश और पुन: उपयोग किए जाते हैं। सज्जाकार सभी में साझा, अपरिवर्तनीय वस्तु का एक सामान्य संदर्भ होगा। यदि सजाया गया राज्य केवल आंशिक रूप से भिन्न होता है, तो डेकोरेटर्स को भी कुछ सीमा तक साझा किया जा सकता है - चूँकि ध्यान रखा जाना चाहिए कि उनका उपयोग किए जाने के समय उनकी स्थिति में बदलाव न हो। iOS का UITableView फ्लाईवेट पैटर्न को इस विधि से प्रायुक्त करता है - एक टेबलव्यू की पुन: प्रयोज्य कोशिकाएं सज्जाकार होती हैं जिनमें एक सामान्य टेबलव्यू पंक्ति वस्तु के संदर्भ होते हैं, और कोशिकाओं को कैश / पुन: उपयोग किया जाता है।

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

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

उपरोक्त कारणों से डेकोरेटरों को अधिकांश उप-वर्गीकरण के लिए स्मृति-कुशल विकल्प माना जाता है।

डेकोरेटर्स का उपयोग उन वस्तुओं को विशेषज्ञ बनाने के लिए भी किया जा सकता है जो उपवर्गीय नहीं हैं, जिनकी विशेषताओं को रनटाइम पर बदलने की आवश्यकता है (जैसा कि कहीं और उल्लेख किया गया है), या सामान्यतः ऐसी वस्तुएं जिनमें कुछ आवश्यक कार्यक्षमता की कमी है।

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

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

यह एक हाइब्रिड पैटर्न है - एकीकृत इंटरफ़ेस वृद्धि के लिए स्थान प्रदान करता है। डेकोरेटरों के बारे में सोचें कि वे व्यक्तिगत वस्तुओं को लपेटने तक सीमित नहीं हैं, किन्तु इस संकर दृष्टिकोण में वस्तुओं के समूहों को लपेटने में भी सक्षम हैं।

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

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

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

सी ++
यहां दो विकल्प प्रस्तुत किए गए हैं: पहला, एक डायनेमिक, रनटाइम-कंपोज़ेबल डेकोरेटर (सजाए गए कार्यों को कॉल करने में समस्या है जब तक कि स्पष्ट रूप से प्रॉक्सी न हो) और एक डेकोरेटर जो मिक्सिन इनहेरिटेंस का उपयोग करता है।

स्टेटिक डेकोरेटर (मिक्सिन इनहेरिटेंस)
यह उदाहरण एक स्थिर डेकोरेटर कार्यान्वयन को प्रदर्शित करता है, जो टेम्पलेट तर्क से इनहेरिट करने की C++ क्षमता के कारण संभव है।

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

नीचे टेस्ट ड्रिवेन डेवलपमेंट के लिए JUnit टेस्ट वर्ग है

दूसरा उदाहरण (कॉफी बनाने का परिदृश्य)
अगला जावा उदाहरण कॉफी बनाने के परिदृश्य का उपयोग करते हुए डेकोरेटरों के उपयोग को दिखाता है।

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

पायथन
निम्नलिखित पायथन उदाहरण, Python Wiki - डेकोरेटरपैटर्न से लिया गया है, हमें दिखाता है कि किसी वस्तु में गतिशील रूप से कई व्यवहारों को जोड़ने के लिए पाइपलाइन डेकोरेटर्स कैसे करें: टिप्पणी:

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

दूसरा पायथन विकी के लिए:

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

क्रिस्टल
आउटपुट:

सी#
आउटपुट:

रूबी
आउटपुट:

यह भी देखें

 * समग्र पैटर्न
 * एडेप्टर पैटर्न
 * सार वर्ग
 * सार कारखाना
 * पहलू आधारित प्रोग्रामिंग
 * अपरिवर्तनीय वस्तु

बाहरी संबंध

 * Decorator Pattern implementation in Java
 * Decorator pattern description from the Portland Pattern Repository