एक ही सदस्यों के साथ दो संरचनाएं लेकिन अलग-अलग नामकरण, क्या यह एक अच्छा विचार है?


49

मैं एक कार्यक्रम लिख रहा हूं जिसमें ध्रुवीय और कार्तीय निर्देशांक दोनों के साथ काम करना शामिल है।

क्या यह हर तरह के बिंदुओं के लिए दो अलग-अलग संरचनाएं बनाने के लिए समझ में आता है, एक Xऔर Yसदस्यों के साथ और एक साथ Rऔर Thetaसदस्यों के लिए।

या यह बहुत अधिक है और सदस्यों के साथ firstऔर केवल एक संरचना होना बेहतर है second

मैं जो लिख रहा हूं वह सरल है और यह ज्यादा नहीं बदलेगा। लेकिन मैं उत्सुक हूं कि डिजाइन के दृष्टिकोण से क्या बेहतर है।

मैं सोच रहा हूं कि पहला विकल्प बेहतर है। यह अधिक पठनीय लगता है और मुझे टाइप चेकिंग का लाभ मिलेगा।


11
मैं हमेशा प्रति उद्देश्य एक नई संरचना / वर्ग बनाता हूं। एक 3 डी वेक्टर की आवश्यकता है, तीन फ्लोट के साथ एक संरचना 3D_vector बनाएं। एक uvw प्रतिनिधित्व की आवश्यकता है, तीन फ्लोट के साथ एक संरचनात्मक बनावट_कोर्ड बनाएं। 3 डी वातावरण में एक स्थिति की आवश्यकता है, तीन झांकियों के साथ एक संरचनात्मक स्थिति बनाएं। तुम समझ गए। यह एक ही चीज़ का उपयोग करने की तुलना में कहीं अधिक बेहतर पठनीयता की अनुमति देता है। यदि आप एक ही चीज़ को कई बार परिभाषित करके परेशान होते हैं, तो आधार 3-फ्लोट-स्ट्रक्चर का उपयोग करें और उसी संरचना होने के लिए कई नामों को परिभाषित करें।
केविन

अगर उनके पास कुछ सामान्य तरीके हैं तो शायद एक है। क्या आपको कभी दोनों की समानता की तुलना करने की आवश्यकता होगी?
पपराज़ो

8
@Sidney जब तक आपको पूरी तरह से कार्यक्षमता की आवश्यकता नहीं है, मैं नहीं करूँगा। आपको दो अभ्यावेदन के बीच कनवर्ट करने के लिए एक पाप / आर्किसिन ऑपरेशन करने की आवश्यकता है। यह हर बार रूपांतरण करते समय कम से कम महत्वपूर्ण बिट्स में थोड़ा सा बिट्रोट पेश करने वाला है। मैं लगभग निश्चित हूं कि आप एक समान दर्द से जूझ रहे हैं जो मैं एक वर्ग से निपटने की कोशिश कर रहा था जो एक घटना आवृत्ति और घटनाओं (x और 1 / x) के बीच का समय प्रदान करता था। यह दर्शाना कि कौन सा प्रतिनिधित्व वर्ग में तोप का गोला है और सभी गोल सिर दर्द से निपटना कुछ ऐसा नहीं है जिसे मैं फिर से करना चाहता हूं।
डैन नीली

3
डेटाटाइप का एक अच्छा उदाहरण जो बहुत सारी चीजों का प्रतिनिधित्व कर सकता है वह स्ट्रिंग है, लेकिन "स्ट्राई टाइप" एक एंटीपैटर्न है। अपना उदाहरण लिखिए। एक प्रकार के लिए डॉट उत्पाद को लागू करने का प्रयास करें जो दोनों समन्वय प्रणालियों का समर्थन करता है।
नाथन कूपर

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

जवाबों:


17

मैंने दोनों समाधान देखे हैं, इसलिए यह निश्चित रूप से संदर्भ पर निर्भर है।

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

चरम समाधान (जिसे हमने अंततः दिया था) एक CRTP टेम्पर्ड बेस क्लास है जिसमें कार्यों को प्राप्त करने के लिए <0> () <1> () प्राप्त करें और <2> () को सामान्य तरीके से प्राप्त करें। उन कार्यों को तब कार्टेशियन या ध्रुवीय संरचना में परिभाषित किया गया है जो इस आधार वर्ग से प्राप्त होता है। यह सभी समस्याओं को हल करता है, लेकिन एक मूर्खतापूर्ण मूल्य पर आता है: टेम्पलेट मेटाप्रोग्रामिंग सीखना। हालाँकि, यदि टेम्पलेट मेटाप्रोग्रामिंग आपकी परियोजना के लिए पहले से ही उचित खेल है, तो यह एक अच्छा मैच हो सकता है।


1
आपका जवाब बहुत दिलचस्प है। क्या एक उदाहरण देना संभव है?
मोहम्मदी ऊँट ऊँट

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

1
मेरी पहली प्रतिक्रिया यह थी कि इस तरह की स्थिति को कास्टिंग द्वारा बेहतर हल किया जाएगा, लेकिन यह कुछ हद तक जोखिम भरा है
200_success

114

हां, यह बहुत मायने रखता है।

एक संरचना का मूल्य सिर्फ इतना नहीं है कि यह एक आसान नाम के तहत डेटा को एन्क्रिप्ट करता है। मूल्य यह है कि यह आपके इरादों को संहिताबद्ध करता है ताकि संकलक यह सत्यापित करने में आपकी सहायता कर सके कि आप किसी दिन उनका उल्लंघन नहीं करते हैं (उदाहरण के लिए एक ध्रुवीय समन्वय सेट के लिए एक ध्रुवीय समन्वय सेट गलती)।

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


6
+1 कंप्यूटर का उपयोग करने के लिए कंप्यूटर का उपयोग करने में क्या अच्छा है, और अपने मस्तिष्क को अपनी खुद की नौकरी पर ध्यान केंद्रित करने का एक सटीक विवरण।
ब्रायन एचएच

8
"प्रोग्राम लोगों को पढ़ने के लिए लिखा जाना चाहिए, और केवल मशीनों को निष्पादित करने के लिए संयोग से।" - एबेल्सन और सुस्मान द्वारा "कंप्यूटर प्रोग्राम की संरचना और व्याख्या" से।
हवलदार

18

हां, जबकि कार्टेशियन और पोलर दोनों अपनी जगह पर हैं (उल्लेखनीय रूप से समझदार समन्वय प्रतिनिधित्व योजनाएं), उन्हें आदर्श रूप से कभी नहीं मिलाया जाना चाहिए (यदि आपके पास कार्टेशियन {1,1} है, तो यह पोलर {1,1 से बहुत अलग बिंदु है) })।

अपनी आवश्यकताओं पर निर्भर करता है, यह भी एक इंटरफेस समन्वय, जैसे तरीकों के साथ लागू करने लायक हो सकता है X(), Y(), Displacement()और Angle()(या शायद Radius()और Theta(), के आधार पर)।


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

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

और इस उदाहरण के लिए भी, यह बदलने की संभावना नहीं है, लेकिन अगर वे 2 अन्य वर्ग थे, तो कुछ भी नहीं बताता है कि वे कुछ बिंदुओं पर विचलन कर सकते हैं।
डाइडेसीज

8

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

आप बस एक struct सदस्यों के साथ नामित करते हैं firstऔर secondहै, तो नाम का कोई मतलब नहीं है, आप अनिवार्य रूप से उन्हें स्मृति पतों के रूप में मानेंगे। यह उच्च-स्तरीय प्रोग्रामिंग भाषा के उद्देश्य को पराजित करता है।

इसके अलावा, सिर्फ इसलिए कि वे सभी प्रतिनिधित्व करने योग्य होते हैं क्योंकि doubleइसका मतलब यह नहीं है कि आप उन्हें परस्पर उपयोग कर सकते हैं। उदाहरण के लिए, θ , एक आयामरहित कोण है, जबकि y लंबाई इकाइयां हैं। चूंकि प्रकार तार्किक रूप से प्रतिस्थापन योग्य नहीं हैं, इसलिए उन्हें दो असंगत संरचनाएं होना चाहिए।

यदि आपको वास्तव में मेमोरी-रियूज़ ट्रिक्स खेलने की आवश्यकता है - और आपको लगभग निश्चित रूप से नहीं करना चाहिए - तो आप unionअपना इरादा स्पष्ट करने के लिए C में एक प्रकार का उपयोग कर सकते हैं ।


सबसे अच्छा जवाब, IMHO
डीन रेडक्लिफ

2

सबसे पहले, दोनों स्पष्ट रूप से, @ केलियन-फोथ के पूरी तरह से ध्वनि उत्तर के अनुसार है।

हालाँकि, मैं जोड़ना चाहूंगा:

पूछें: क्या आपके पास वास्तव में ऐसे ऑपरेशन हैं जो जोड़े के रूप में माने जाते हैं double? इस पर ध्यान न दें कि यह कहना कि आपके पास ऐसे ऑपरेशन हैं जो अपनी शर्तों पर दोनों पर लागू होते हैं। उदाहरण के लिए 'प्लॉट (कोर्ड)' परवाह करता है कि क्या Coordपोलर या कार्टेशियन है। दूसरी ओर, फ़ाइल को जारी रखने से डेटा उसी तरह व्यवहार करता है जैसा वह है। क्या तुम सच में सामान्य ऑपरेशन करते हैं, पर विचार या तो एक आधार वर्ग को परिभाषित करने, या एक के लिए एक कनवर्टर को परिभाषित करने std::pair<double, double>या tupleया जो भी आप अपनी भाषा में है।

इसके अलावा, एक दृष्टिकोण एक समन्वय प्रकार को अधिक मौलिक और दूसरे को केवल उपयोगकर्ता या बाहरी संपर्क के लिए समर्थन के रूप में माना जा सकता है।

इसलिए आप यह सुनिश्चित कर सकते हैं कि सभी मूलभूत परिचालनों के लिए कोडित किया गया है Cartesianऔर फिर परिवर्तित Polarकरने के लिए समर्थन प्रदान किया जाएगा Cartesian। यह कई ऑपरेशन के विभिन्न संस्करणों को लागू करने से बचा जाता है।


1

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

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

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


दोनों वर्गों में सदस्यों के नाम समान नहीं हैं। वास्तव में नाम केवल दो वर्गों के बीच का अंतर है
मोह अलम्मी ऊंट

@ Mhd.Tahawi आप उचित नामों के साथ गेटर्स और सेटरर्स को लागू कर सकते हैं, यह सुनिश्चित करते हुए कि आप जिस वर्ग का उपयोग कर रहे हैं, वह समान है, लेकिन आप जिन ऑपरेशन्स का उपयोग करना चाहते हैं, उनके लिए उपयुक्त नाम प्रदान करना। यह थोड़ा और अधिक हो जाता है, लेकिन आपको कम कोड की नकल करनी होगी।
स्वावलोरन

0

मेरा मानना ​​है कि इस मामले में एक ही सदस्य के नाम होना एक बुरा विचार है, क्योंकि यह कोड को अधिक त्रुटि प्रवण बनाता है।

परिदृश्य की कल्पना करें: आपके पास कार्टेशियन अंक के कुछ जोड़े हैं: pntA और pntB। फिर आप तय करते हैं, किसी कारण के लिए, कि उन्हें ध्रुवीय निर्देशांक में बेहतर प्रतिनिधित्व किया जाना चाहिए, और घोषणा और निर्माणकर्ता को बदलना चाहिए।

अब, यदि आपके सभी ऑपरेशन केवल विधि कॉल थे जैसे:

double distance = pntA.distanceFrom(pntB);

फिर तुम ठीक हो। लेकिन क्या होगा यदि आप सदस्यों को स्पष्ट रूप से उपयोग करते हैं? तुलना

double leftMargin = abs(pntA.x - pntB.x);
double leftMargin = abs(pntA.first - pntB.first);

पहले मामले में, कोड संकलन नहीं करेगा। आपको तुरंत त्रुटि दिखाई देगी और इसे ठीक करने में सक्षम होंगे। लेकिन अगर आपके पास एक ही सदस्य के नाम हैं, तो त्रुटि केवल तार्किक स्तर पर होगी, यह पता लगाने के लिए बहुत कठिन है।

यदि आप एक गैर-ऑब्जेक्ट-ओरिएंटेड भाषा में लिखते हैं, तो फ़ंक्शन के लिए गलत संरचना को पारित करना और भी आसान है। आपको निम्नलिखित कोड लिखने से रोकने के लिए क्या है?

double distance = calculate_distance_polar(cartesianPointA, polarPointB);

दूसरी ओर, विभिन्न प्रकार के डेटा आपको संकलन के दौरान त्रुटि खोजने की अनुमति देते हैं।

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