क्या हम वास्तव में सभी प्रमुख OOP सुविधाओं को खोए बिना OOP में अपरिवर्तनीयता का उपयोग कर सकते हैं?


11

मैं अपने कार्यक्रम में वस्तुओं को अपरिवर्तनीय बनाने के लाभ देखता हूं। जब मैं वास्तव में अपने आवेदन के लिए एक अच्छे डिजाइन के बारे में गहराई से सोच रहा हूं तो मैं स्वाभाविक रूप से अपनी कई वस्तुओं को अपरिवर्तनीय रूप से प्राप्त करता हूं। यह अक्सर उस बिंदु पर आता है जहां मैं अपनी सभी वस्तुओं को अपरिवर्तनीय रखना चाहूंगा ।

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

मेरा अनुभव है कि अपरिवर्तनीयता मेरे कोड को कार्यात्मक प्रतिमान तक ले जाती है और यह प्रगति हमेशा होती है:

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

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

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


3
मुझे आधार प्रश्न पसंद है, लेकिन मेरे पास विवरण के साथ एक कठिन समय है। उदाहरण के लिए जब आप अपरिवर्तनीयता को अधिकतम करने के लिए वंशानुक्रम को रोकते हैं तो यह क्यों होता है?
मार्टिन बा

1
आपकी वस्तुओं में विधियाँ नहीं हैं?
मोनिका


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

1
@ लिसाक आप "सरल शब्दों में विरासत के साथ समस्या को समझाने के लिए संघर्ष" क्योंकि यह कोई समस्या नहीं है; खराब डिजाइन एक समस्या है। वंशानुक्रम ओओपी का बहुत सार है, यदि आप करेंगे तो साइन योग्यता नॉन । तथाकथित "इनहेरिटेंस के साथ समस्याएँ" वास्तव में एक स्पष्ट ओवरराइड सिंटैक्स न होने वाली भाषाओं की समस्याएं हैं, और वे बेहतर डिज़ाइन की गई भाषाओं में बहुत कम समस्याग्रस्त हैं। आभासी तरीकों और बहुरूपता के बिना, आपके पास OOP नहीं है; आपके पास फनी ऑब्जेक्ट सिंटैक्स के साथ प्रक्रियात्मक प्रोग्रामिंग है। तो यह कोई आश्चर्य नहीं है कि यदि आप इसे टाल रहे हैं तो आपको OO के लाभ दिखाई नहीं दे रहे हैं!
मेसन व्हीलर

जवाबों:


24

क्या हम वास्तव में सभी प्रमुख OOP सुविधाओं को खोए बिना OOP में अपरिवर्तनीयता का उपयोग कर सकते हैं?

क्यों नहीं देखा। जावा 8 साल से पहले यह कर रहा था वैसे भी सभी कार्यात्मक। कभी स्ट्रिंग्स के बारे में सुना है? शुरू से ही अच्छा और अपरिवर्तनीय है।

  1. मुझे सूची, मानचित्र आदि जैसे डेटा संरचनाओं में लगातार (कार्यात्मक अर्थों में) की आवश्यकता है।

जरूरत है उन सभी के साथ-साथ। मेरे पुनरावृत्तियों को अमान्य करना क्योंकि आपने संग्रह को म्यूट कर दिया था जब मैं पढ़ रहा था तो यह केवल असभ्य था।

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

परिपत्र संदर्भ एक विशेष प्रकार का नरक है। अभेद्यता आपको इससे नहीं बचाएगी।

  1. वंशानुक्रम किसी भी अर्थ को बनाने के लिए रुक जाता है और मैं इसके बजाय रचना का उपयोग करना शुरू कर देता हूं।

यहाँ मैं तुम्हारे साथ हूँ, लेकिन यह नहीं देख पा रहा हूँ कि इसे अपरिवर्तनीयता के साथ क्या करना है। रचना पसंद करने का कारण यह नहीं है कि मुझे डायनेमिक रणनीति पैटर्न पसंद है, यह इसलिए है क्योंकि इससे मुझे अपने स्तर को अमूर्त करने में मदद मिलती है।

  1. ओओपी के पूरे मूल विचार जैसे एनकैप्सुलेशन अलग होने लगते हैं और मेरी वस्तुएं कार्यों की तरह दिखना शुरू हो जाती हैं।

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

आपकी वस्तुओं को कार्यों की तरह माना जाता है। वे कार्यों के बैग हैं। वे कार्यों के बैग हैं जो एक साथ चलते हैं और एक साथ खुद को फिर से परिभाषित करते हैं।

कार्यात्मक प्रोग्रामिंग इस समय प्रचलित है और लोग OOP के बारे में कुछ गलत धारणाएं बना रहे हैं। ऐसा मत होने दो कि आपको विश्वास हो जाए कि यह OOP का अंत है। कार्यात्मक और ओओपी काफी अच्छी तरह से एक साथ रह सकते हैं।

  • असाइनमेंट के बारे में कार्यात्मक प्रोग्रामिंग औपचारिक है।

  • OOP फंक्शन पॉइंटर्स के बारे में औपचारिक बताया जा रहा है।

वास्तव में यह है कि Dykstra ने बताया कि gotoयह हानिकारक था इसलिए हमने इसके बारे में औपचारिकता की और संरचित प्रोग्रामिंग बनाई। ठीक वैसे ही, ये दोनों प्रतिमान उन परेशानियों से दूर रहने के दौरान चीजों को पाने के तरीकों को खोजने के बारे में हैं जो इन परेशानियों को व्यक्तिगत रूप से करने से आते हैं।

चलिए मैं आपको कुछ दिखाता हूँ:

f n (x)

वह एक फंक्शन है। यह वास्तव में कार्यों का एक सिलसिला है:

f 1 (x)
f 2 (x)
...
f n (x)

लगता है कि हम कैसे OOP भाषाओं में व्यक्त करते हैं?

n.f(x)

वह थोड़ा nचुनता है कि किस कार्यान्वयन का fउपयोग किया जाता है और यह तय करता है कि उस फ़ंक्शन में उपयोग किए गए कुछ स्थिरांक क्या हैं (जो स्पष्ट रूप से एक ही बात का मतलब है)। उदाहरण के लिए:

f 1 (x) = x + 1
f 2 (x) = x + 2

यही बात क्लोजर प्रदान करती है। जहां क्लोजर उनके एन्कोडिंग स्कोप का संदर्भ देते हैं, ऑब्जेक्ट मेथड्स उनके इंस्टेंस स्टेट का संदर्भ देते हैं। ऑब्जेक्ट एक बेहतर बंद कर सकते हैं। एक क्लोजर एकल फ़ंक्शन दूसरे फ़ंक्शन से लौटाया गया है। एक निर्माणकर्ता कार्यों के पूरे बैग का संदर्भ देता है:

g 1 (x) = x 2 + 1
g 2 (x) = x 2 + 2

हां, आपने अनुमान लगाया:

n.g(x)

f और g ऐसे कार्य हैं जो एक साथ बदलते हैं और एक साथ घूमते हैं। तो हम उन्हें एक ही बैग में चिपका देते हैं। यह वास्तव में एक वस्तु है। होल्डिंग nनिरंतर (अपरिवर्तनीय) बस यह भविष्यवाणी करने के लिए क्या इन जब आप उन्हें फोन करना होगा आसान है का मतलब है।

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

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

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

आर्ग! फिर से अनावश्यक परिपत्र संदर्भों के साथ।

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

रुको, हम शतरंज के बारे में पहले से ही बात नहीं करते थे?



1
और अंतिम लेकिन कम से कम ऑरलैंडो की संधि नहीं ।
जोर्ग डब्ल्यू मित्तग

1
@ यूफोरिक: मुझे लगता है कि यह एक काफी मानक सूत्रीकरण है जो "कार्यात्मक प्रोग्रामिंग", "अनिवार्य प्रोग्रामिंग", "लॉजिक प्रोग्रामिंग", आदि के लिए मानक परिभाषाओं से मेल खाता है, अन्यथा, सी एक कार्यात्मक भाषा है क्योंकि आप इसमें एफपी को एन्कोड कर सकते हैं, एक लॉजिक लैंग्वेज, क्योंकि आप इसमें लॉजिक प्रोग्रामिंग को एनकोड कर सकते हैं, एक डायनेमिक लैंग्वेज, क्योंकि आप इसमें डायनामिक टाइपिंग को एनकोड कर सकते हैं, एक एक्टर लैंग्वेज, क्योंकि आप इसमें एक्टर सिस्टम को एनकोड कर सकते हैं, और इसी तरह। और हास्केल दुनिया की सबसे बड़ी अनिवार्य भाषा है क्योंकि आप वास्तव में दुष्प्रभावों का नाम दे सकते हैं, उन्हें चर में स्टोर कर सकते हैं, उन्हें पास कर सकते हैं ...
Jörg W Mittag

1
मुझे लगता है कि हम इसी तरह के विचारों को मैथियास फेलिसन के जीनियस पेपर में भाषा अभिव्यक्ति के बारे में इस्तेमाल कर सकते हैं। एक OO प्रोग्राम को आगे बढ़ाते हुए, कहते हैं, जावा से C transform को केवल स्थानीय परिवर्तनों के साथ किया जा सकता है, लेकिन इसे C में स्थानांतरित करने के लिए एक वैश्विक पुनर्गठन की आवश्यकता होती है (मूल रूप से, आपको एक संदेश प्रेषण तंत्र की आवश्यकता होती है और इसके माध्यम से सभी फ़ंक्शन कॉल पुनर्निर्देशित करते हैं), इसलिए जावा और C only OO को व्यक्त कर सकते हैं और C इसे केवल "एनकोड" कर सकते हैं।
जोर्ग डब्ल्यू मित्तग

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

2

ओओपी द्वारा मुख्य धारा में पेश की जाने वाली सबसे उपयोगी अवधारणाएं मेरे दिमाग में हैं:

  • उचित संशोधन।
  • डेटा इनकैप्सुलेशन।
  • निजी और सार्वजनिक इंटरफेस के बीच स्पष्ट अलगाव।
  • कोड विस्तार के लिए स्पष्ट तंत्र।

इन सभी लाभों को पारंपरिक कार्यान्वयन विवरण के बिना भी महसूस किया जा सकता है, जैसे वंशानुक्रम या यहां तक ​​कि कक्षाएं। एलन कै के मूल विचार "ऑब्जेक्ट-ओरिएंटेड सिस्टम" का प्रयोग "मेसेज" के बजाय "मेथड्स" के रूप में किया जाता था, और उदाहरणार्थ C ++ की तुलना में एर्लांग के करीब था। गो को देखें जो कई पारंपरिक ओओपी कार्यान्वयन विवरणों के साथ दूर करता है, लेकिन फिर भी यथोचित वस्तु-उन्मुखता महसूस करता है।

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

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

भाषा रचनाकारों की तुलना में एक अलग दृष्टिकोण की कोशिश करने के साथ सामान्य समस्या एन साल पहले मन में थी, मानक पुस्तकालय के साथ 'प्रतिबाधा बेमेल' है। OTOH जावा और .NET पारिस्थितिकी तंत्र दोनों में वर्तमान में अपरिवर्तनीय डेटा संरचनाओं के लिए उचित मानक-पुस्तकालय समर्थन है; बेशक, तीसरे पक्ष के पुस्तकालय भी मौजूद हैं।

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