अभ्यास में खुले-बंद सिद्धांत का पालन कैसे करें


15

मैं खुले-बंद सिद्धांत के इरादे को समझता हूं। इसका मतलब यह है कि किसी चीज को तोड़ने का जोखिम कम करना, जो पहले से ही इसे संशोधित करते हुए काम करता है, आपको बताए बिना संशोधित करने की कोशिश करता है।

हालांकि, मुझे यह समझने में थोड़ी परेशानी हुई कि यह सिद्धांत व्यवहार में कैसे लागू होता है। मेरी समझ से, इसे लागू करने के दो तरीके हैं। Beofore और एक संभावित परिवर्तन के बाद:

  1. इससे पहले: अमूर्त करने के लिए कार्यक्रम और 'भविष्य की भविष्यवाणी' जितना आप कर सकते हैं। उदाहरण के लिए, drive(Car car)यदि Motorcycleभविष्य में सिस्टम में एस जोड़ा जाता है, तो एक विधि को बदलना होगा, इसलिए यह संभवतः ओसीपी का उल्लंघन करता है। लेकिन drive(MotorVehicle vehicle)भविष्य में विधि को बदलने की संभावना कम है, इसलिए यह ओसीपी का पालन करता है।

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

  2. इसके बाद: जब परिवर्तन की आवश्यकता होती है, तो वर्तमान कोड को संशोधित करने के बजाय एक वर्ग का विस्तार करें।

अभ्यास # 1 को समझना मुश्किल नहीं है। हालाँकि यह # 2 अभ्यास है कि मुझे यह समझने में परेशानी हो रही है कि आवेदन कैसे करें।

उदाहरण के लिए (मैंने इसे YouTube पर एक वीडियो से लिया): मान लीजिए कि हमारे पास एक वर्ग में एक विधि है जो CreditCardवस्तुओं को स्वीकार करती है makePayment(CraditCard card):। एक दिन Voucherसिस्टम में जोड़ा जाता है। यह विधि उनका समर्थन नहीं करती है इसलिए इसे संशोधित करना होगा।

पहली बार विधि को लागू करते समय हम भविष्य और कार्यक्रम को और अधिक सार शब्दों में अनुमान लगाने में विफल रहे (जैसे makePayment(Payment pay), इसलिए अब हमें मौजूदा कोड को बदलना होगा।

अभ्यास # 2 कहता है कि हमें संशोधित करने के बजाय कार्यक्षमता को जोड़ना चाहिए। इसका क्या मतलब है? क्या मुझे मौजूदा कोड को बदलने के बजाय मौजूदा वर्ग को उप-वर्ग करना चाहिए? क्या मुझे पुनर्लेखन कोड से बचने के लिए इसके चारों ओर किसी प्रकार का आवरण बनाना चाहिए?

या सिद्धांत यह भी नहीं बताता है कि 'कार्यक्षमता को सही ढंग से कैसे संशोधित / जोड़ना है', बल्कि यह संदर्भित करता है कि 'पहली जगह में परिवर्तन करने के लिए (यानी कार्यक्रम से अमूर्त) कैसे बचें?



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

जवाबों:


14

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

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

व्यवहार में, जब आपके पास केवल दो कार्यान्वयन होते हैं, तो जब आप तीसरे को जोड़ते हैं तो रिफैक्टरिंग करना आमतौर पर बहुत मुश्किल नहीं होता है। यह तब होता है जब आप इसे उस बिंदु से आगे बढ़ने देते हैं कि यह बनाए रखना मुश्किल हो जाता है।


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

1
ये तो कमाल की सोच है।
कार्ल ब्वेलफेल्ट

2

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

मान लीजिए कि आपको एक drive(Car car)विधि लागू करने की आवश्यकता है । आपकी भाषा के आधार पर आपके पास कुछ विकल्प हैं।

  • ओवरलोडिंग (C ++) का समर्थन करने वाली भाषाओं के लिए, फिर उपयोग करें drive(const Car& car)

    कुछ बिंदु पर बाद में आपको आवश्यकता हो सकती है drive(const Motorcycle& motorcycle), लेकिन यह हस्तक्षेप नहीं करेगा drive(const Car& car)। कोई दिक्कत नहीं है!

  • ओवरलोडिंग (ऑब्जेक्टिव C) का समर्थन नहीं करने वाली भाषाओं के लिए, फिर विधि में टाइप नाम शामिल करें -driveCar:(Car *)car

    कुछ बिंदु पर बाद में आपको आवश्यकता हो सकती है -driveMotorcycle:(Motorcycle *)motorcycle, लेकिन फिर से, यह हस्तक्षेप नहीं करेगा।

यह drive(Car car)संशोधन करने के लिए बंद होने की अनुमति देता है, लेकिन अन्य वाहन प्रकारों के विस्तार के लिए खुला है। यह न्यूनतम भविष्य की योजना है जो आपको आज काम करने की अनुमति देता है, लेकिन भविष्य में आपको खुद को अवरुद्ध करने से रोकता है।

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


अपने नए तरीके को जोड़ने के लिए एक वर्ग को संशोधित करना ओपन-क्लोज्ड सिद्धांत का उल्लंघन करता है। आपका सुझाव उन सभी वाहनों के लिए लिस्कोव-प्रतिस्थापन सिद्धांत को लागू करने की क्षमता को भी समाप्त कर देता है जो ड्राइव कर सकते हैं जो अनिवार्य रूप से OO के सबसे मजबूत भागों में से एक को समाप्त करता है।
डंक

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

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

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

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

2

मैं खुले-बंद सिद्धांत के इरादे को समझता हूं। इसका मतलब यह है कि किसी चीज को तोड़ने का जोखिम कम करना, जो पहले से ही इसे संशोधित करते हुए काम करता है, आपको बताए बिना संशोधित करने की कोशिश करता है।

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

इसका क्या मतलब है? क्या मुझे मौजूदा कोड को बदलने के बजाय मौजूदा वर्ग को उप-वर्ग करना चाहिए?

हाँ।

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

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

नया व्यवहार = नई कक्षा

एक तरफ के रूप में - भविष्य की भविष्यवाणी करने का एक अच्छा तरीका उस नाम के बारे में सोचना है जो आपने एक विधि दी है। क्या आपने मेकपमेंट की तरह वास्तव में सामान्य लगने वाली विधि का नाम दिया है, जिसमें विधि में विशिष्ट नियमों के साथ विधि है कि क्या यह भुगतान कर सकता है? यह एक कोड गंध है। यदि आपके पास विशिष्ट नियम हैं, तो उन्हें विधि के नाम से स्पष्ट किया जाना चाहिए - MakePayment को MakeCreditCardPayment होना चाहिए। ऐसा तब करें जब आप पहली बार ऑब्जेक्ट लिख रहे हैं और अन्य प्रोग्रामर इसके लिए आपका धन्यवाद करेंगे।

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