क्यों "बनाम"? यह "बनाम" नहीं है। आप कार्यात्मक प्रोग्रामिंग के साथ संयोजन में पहलू ओरिएंटेड प्रोग्रामिंग का उपयोग कर सकते हैं, लेकिन ऑब्जेक्ट ओरिएंटेड के साथ संयोजन में भी। यह "बनाम" नहीं है, यह " ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग के साथ एस्पेक्ट ओरिएंटेड प्रोग्रामिंग" है।
मेरे लिए AOP कुछ "मेटा-प्रोग्रामिंग" है। सब कुछ जो AOP करता है वह इसके बिना भी किया जा सकता है बस अधिक कोड जोड़कर। AOP आपको यह कोड लिखने से बचाता है।
इस मेटा-प्रोग्रामिंग के लिए विकिपीडिया के सबसे अच्छे उदाहरण हैं। मान लें कि आपके पास कई "सेट ... ()" विधियों के साथ एक ग्राफिकल क्लास है। प्रत्येक सेट विधि के बाद, ग्राफिक्स का डेटा बदल गया, इस प्रकार ग्राफिक्स बदल गया और इस तरह ग्राफिक्स को स्क्रीन पर अपडेट करने की आवश्यकता है। ग्राफिक्स को फिर से पेंट करने के लिए मान लें कि आपको "Display.update ()" को कॉल करना होगा। शास्त्रीय दृष्टिकोण अधिक कोड जोड़कर इसे हल करना है । प्रत्येक सेट विधि के अंत में आप लिखते हैं
void set...(...) {
:
:
Display.update();
}
यदि आपके पास 3 सेट-विधियाँ हैं, तो यह कोई समस्या नहीं है। यदि आपके पास 200 (काल्पनिक) हैं, तो इसे हर जगह जोड़ने के लिए वास्तविक दर्दनाक हो रहा है। जब भी आप एक नया सेट-मेथड जोड़ते हैं, तो आपको इसे अंत तक जोड़ना न भूलें, अन्यथा आपने सिर्फ एक बग बनाया है।
AOP इसे बिना टन के कोड को जोड़कर हल करता है, इसके बजाय आप एक पहलू जोड़ते हैं:
after() : set() {
Display.update();
}
और बस! अपडेट कोड स्वयं लिखने के बजाय, आप बस सिस्टम को बताएं कि एक सेट () पॉइंटकट हो जाने के बाद, उसे इस कोड को चलाना होगा और यह इस कोड को चलाएगा। 200 तरीकों को अपडेट करने की आवश्यकता नहीं है, यह सुनिश्चित करने की आवश्यकता नहीं है कि आप इस कोड को एक नए सेट-मेथड में जोड़ना न भूलें। इसके अतिरिक्त आपको बस एक बिंदु की जरूरत है:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
इसका क्या मतलब है? इसका मतलब है कि अगर किसी विधि को "सेट *" नाम दिया गया है (* इसका मतलब सेट के बाद कोई भी नाम हो सकता है), इस बात की परवाह किए बिना कि विधि कैसे लौटती है (पहला तारांकन) या यह कौन सा पैरामीटर लेता है (तीसरा तारांकन) और यह MyGraphicsClass का एक तरीका है और यह क्लास पैकेज "com.company। *" का हिस्सा है, तो यह एक सेट () पॉइंटकट है। और हमारा पहला कोड कहता है " किसी भी विधि को चलाने के बाद जो एक निर्धारित बिंदु है, निम्न कोड को चलाएं"।
देखें कि कैसे AOP यहाँ समस्या को हल करता है? वास्तव में यहाँ वर्णित सब कुछ संकलन समय पर किया जा सकता है। AOP प्रीप्रोसेसर अपने स्रोत को संशोधित कर सकता है (जैसे कि प्रत्येक सेट-पॉइंटकट विधि के अंत में Display.update () को जोड़कर) यहां तक कि कक्षा को भी संकलित करने से पहले।
हालाँकि, यह उदाहरण AOP की एक बड़ी गिरावट को भी दर्शाता है। एओपी वास्तव में कुछ ऐसा कर रहा है जो कई प्रोग्रामर " एंटी-पैटर्न " मानते हैं । सटीक पैटर्न को " एक्शन एट ए डिस्टेंस " कहा जाता है ।
दूरी पर कार्रवाई एक एंटी-पैटर्न (एक मान्यता प्राप्त सामान्य त्रुटि) है जिसमें कार्यक्रम के एक हिस्से में व्यवहार कार्यक्रम के दूसरे भाग में संचालन की पहचान करने के लिए मुश्किल या असंभव के आधार पर अलग-अलग होता है।
एक परियोजना के लिए एक नौसिखिया के रूप में, मैं बस किसी भी सेट-विधि के कोड को पढ़ सकता हूं और इसे टूटा हुआ मान सकता हूं, क्योंकि ऐसा लगता है कि यह डिस्प्ले को अपडेट नहीं करता है। मैं केवल एक सेट-मेथड के कोड को देखकर नहीं देखता , कि इसे निष्पादित करने के बाद, कुछ अन्य कोड "जादुई रूप से" प्रदर्शन को अपडेट करने के लिए निष्पादित होंगे। मैं इसे एक गंभीर नकारात्मक पक्ष मानता हूं! एक विधि में परिवर्तन करके, अजीब कीड़े पेश किए जा सकते हैं। आगे कोड के प्रवाह को समझना जहां कुछ चीजें सही ढंग से काम करने लगती हैं, लेकिन स्पष्ट नहीं हैं (जैसा कि मैंने कहा, वे सिर्फ जादुई रूप से काम करते हैं ... किसी भी तरह), वास्तव में कठिन है।
अपडेट करें
बस यह स्पष्ट करने के लिए कि: कुछ लोगों को आभास हो सकता है कि मैं कह रहा हूं कि AOP कुछ बुरा है और इसका उपयोग नहीं किया जाना चाहिए। ऐसा मैं नहीं कह रहा हूँ! AOP वास्तव में एक महान विशेषता है। मैं बस कहता हूं "इसे सावधानी से उपयोग करें"। एओपी केवल समस्याओं का कारण होगा यदि आप समान पहलू के लिए सामान्य कोड और एओपी को मिलाते हैं । ऊपर दिए गए उदाहरण में, हमारे पास एक ग्राफिकल ऑब्जेक्ट के मूल्यों को अपडेट करने और अपडेट की गई वस्तु को चित्रित करने का पहलू है। यह वास्तव में एक पहलू है। आधे को सामान्य कोड के रूप में और दूसरे को पहलू के रूप में कोडिंग करना समस्या को जोड़ता है।
यदि आप AOP का उपयोग पूरी तरह से अलग पहलू के लिए करते हैं, जैसे लॉगिंग के लिए, तो आप एंटी-पैटर्न समस्या में नहीं चलेंगे। उस स्थिति में परियोजना के लिए एक नौसिखिया आश्चर्यचकित हो सकता है "ये सभी लॉग संदेश कहां से आते हैं? मुझे कोड में कोई लॉग आउटपुट दिखाई नहीं देता है", लेकिन यह एक बड़ी समस्या नहीं है। वह प्रोग्राम लॉजिक में जो परिवर्तन करता है, वह लॉग सुविधा को तोड़ देगा और लॉग सुविधा में किए गए परिवर्तन शायद ही उसके प्रोग्राम लॉजिक को तोड़ेंगे - ये पहलू पूरी तरह से अलग हैं। लॉगिंग के लिए एओपी का उपयोग करने से यह लाभ होता है कि आपका प्रोग्राम कोड पूरी तरह से जो कुछ भी करना चाहिए उस पर ध्यान केंद्रित कर सकता है और आपके पास अभी भी परिष्कृत लॉगिंग हो सकती है, बिना आपके कोड को हर जगह सैकड़ों लॉग मैसेज से क्लू किया जा सकता है। साथ ही जब नया कोड पेश किया जाता है, तो जादुई रूप से लॉग संदेश सही सामग्री के साथ सही समय पर दिखाई देंगे।
तो मेरे उदाहरण में AOP का एक अच्छा उपयोग हमेशा लॉग इन करना होगा यदि किसी मूल्य को एक सेट विधि के माध्यम से अद्यतन किया गया है। यह एक विरोधी पैटर्न नहीं बनाएगा और शायद ही कभी किसी समस्या का कारण होगा।
कोई कह सकता है, यदि आप AOP को इतनी सारी समस्याएं पैदा करने के लिए आसानी से दुरुपयोग कर सकते हैं, तो यह सब का उपयोग करने के लिए एक बुरा विचार है। हालाँकि किस तकनीक का दुरुपयोग नहीं किया जा सकता है? आप डेटा इनकैप्सुलेशन का दुरुपयोग कर सकते हैं, आप वंशानुक्रम का दुरुपयोग कर सकते हैं। बहुत ज्यादा हर उपयोगी प्रोग्रामिंग तकनीक का दुरुपयोग किया जा सकता है। एक प्रोग्रामिंग भाषा पर इतना सीमित विचार करें कि इसमें केवल ऐसी विशेषताएं हैं जो दुरुपयोग नहीं की जा सकती हैं; एक ऐसी भाषा जहां सुविधाओं का उपयोग किया जा सकता है क्योंकि वे शुरू में उपयोग करने के लिए अभिप्रेत थीं। इस तरह की भाषा इतनी सीमित होगी कि अगर यह वास्तविक विश्व प्रोग्रामिंग के लिए भी इस्तेमाल किया जा सकता है तो यह तर्क संगत है।