सी में इंटरफ़ेस अलगाव सिद्धांत कैसे लागू करें?


15

मेरे पास एक मॉड्यूल है, 'M', जिसके कुछ ग्राहक हैं, 'C1', 'C2', 'C3' कहते हैं। मैं मॉड्यूल M के नाम स्थान, यानी एपीआई और डेटा की घोषणाओं को हेडर फ़ाइल (ओं) में इस तरह से अपीयर करना चाहता हूं कि -

  1. किसी भी क्लाइंट के लिए केवल डेटा और API की आवश्यकता होती है जो दिखाई देता है; मॉड्यूल के बाकी नामस्थान क्लाइंट से छिपे हुए हैं अर्थात इंटरफ़ेस सेग्रीगेशन सिद्धांत का पालन करते हैं
  2. कई हेडर फ़ाइलों में एक घोषणा को दोहराया नहीं जाता है अर्थात DRY का उल्लंघन नहीं किया जाता है ।
  3. मॉड्यूल M का अपने ग्राहकों पर कोई निर्भरता नहीं है।
  4. एक क्लाइंट मॉड्यूल M के कुछ हिस्सों में किए गए परिवर्तनों से अप्रभावित है जो इसका उपयोग नहीं करते हैं।
  5. मौजूदा क्लाइंट अधिक क्लाइंट्स को जोड़ने (या हटाने) से अप्रभावित रहते हैं।

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

मॉड्यूल नाम स्थान विभाजन

हालाँकि, यह कुछ पूर्वोक्त आवश्यकताओं अर्थात R3 और R5 का उल्लंघन करता है। आवश्यकता 3 का उल्लंघन किया जाता है क्योंकि यह विभाजन ग्राहकों की प्रकृति पर निर्भर करता है; एक नए ग्राहक के अलावा यह विभाजन बदलता है और आवश्यकता का उल्लंघन करता है। 5. जैसा कि ऊपर की छवि के दाईं ओर देखा जा सकता है, एक नए ग्राहक के अलावा मॉड्यूल का नाम स्थान अब 7 हेडर फ़ाइलों में विभाजित है - 'a ',' बी ',' सी ',' 1 ',' 2 * ',' 3 * 'और' 4 ' । शीर्ष लेख फ़ाइलों में से 2 पुराने ग्राहकों के लिए है, जिससे उनका पुनर्निर्माण शुरू हो रहा है।

क्या गैर-कंट्रोल्ड तरीके से सी में इंटरफ़ेस अलगाव को प्राप्त करने का एक तरीका है?
यदि हाँ, तो आप उपरोक्त उदाहरण से कैसे निपटेंगे?

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


1
यह समस्या C के लिए विशिष्ट क्यों है? क्या इसलिए कि सी में विरासत नहीं है?
रॉबर्ट हार्वे

इसके अलावा, क्या आईएसपी का उल्लंघन करने से आपके डिजाइन का काम बेहतर होता है?
रॉबर्ट हार्वे

2
सी वास्तव में आंतरिक रूप से OOP अवधारणाओं (जैसे इंटरफेस या विरासत) का समर्थन नहीं करता है। हम क्रूड (लेकिन रचनात्मक) हैक्स के साथ करते हैं। इंटरफेस की नकल करने के लिए एक हैक की तलाश में। आमतौर पर, पूरी हेडर फ़ाइल एक मॉड्यूल के लिए इंटरफ़ेस है।
.बीन

1
structजब आप इंटरफ़ेस चाहते हैं, तो आप C में किसका उपयोग करते हैं। दी, तरीके थोड़े कठिन हैं। आपको यह दिलचस्प लग सकता है: cs.rit.edu/~ats/books/ooc.pdf
रॉबर्ट हार्वे

मैं एक अंतरफलक बराबर का उपयोग कर के साथ नहीं आ सकता है structऔर function pointers
.बीन

जवाबों:


5

इंटरफ़ेस अलगाव, सामान्य तौर पर, ग्राहक की आवश्यकताओं पर आधारित नहीं होना चाहिए। आपको इसे प्राप्त करने के लिए पूरे दृष्टिकोण को बदलना चाहिए। मैं कहूंगा, सुसंगत समूहों में सुविधाओं को समूहीकृत करके इंटरफ़ेस को संशोधित करें । वह समूहीकरण स्वयं सुविधाओं की सुसंगतता पर आधारित है, न कि क्लाइंट आवश्यकताओं के आधार पर। उस स्थिति में, आपके पास इंटरफेस, I1, I2, ... आदि का एक सेट होगा। क्लाइंट C1 अकेले I2 का उपयोग कर सकता है। क्लाइंट C2 I1 और I5 आदि का उपयोग कर सकता है। ध्यान दें, यदि ग्राहक एक से अधिक Ii का उपयोग करता है, तो कोई समस्या नहीं है। यदि आपने इंटरफ़ेस को सुसंगत मॉड्यूल में विघटित कर दिया है, तो यह वह जगह है जहां मामले का दिल है।

फिर से, ISP क्लाइंट-आधारित नहीं है। यह छोटे मॉड्यूल में इंटरफ़ेस को विघटित करने के बारे में है। यदि यह ठीक से किया जाता है, तो यह भी सुनिश्चित करेगा कि ग्राहकों को कम से कम सुविधाओं के रूप में उजागर किया जाए।

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


आप निश्चित रूप से असहमति या गैर-अतिव्यापी समूहों का मतलब है , मुझे लगता है?
डॉक ब्राउन

हां, असहमति और गैर-अतिव्यापी।
नजर मेरजा

3

इंटरफ़ेस पृथक्करण सिद्धांत का कहना है:

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

यहाँ कुछ अनुत्तरित प्रश्न हैं। एक है:

कितना छोटा?

तुम कहो:

वर्तमान में मैं इसके क्लाइंट की आवश्यकताओं के आधार पर मॉड्यूल के नाम स्थान को विभाजित करके इससे निपटता हूं।

मैं इस मैनुअल बतख टाइपिंग को कॉल करता हूं । आप उन इंटरफेस का निर्माण करते हैं जो केवल एक ग्राहक की जरूरत को उजागर करते हैं। इंटरफ़ेस पृथक्करण सिद्धांत केवल मैनुअल बतख टाइपिंग नहीं है।

लेकिन आईएसपी केवल "सुसंगत" भूमिका इंटरफेस के लिए एक कॉल नहीं है जिसका पुन: उपयोग किया जा सकता है। कोई "सुसंगत" रोल इंटरफ़ेस डिजाइन पूरी तरह से एक नए ग्राहक को जोड़ने के खिलाफ नहीं है, जिसके पास इसकी स्वयं की भूमिका की आवश्यकता है।

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

यह इंटरफ़ेस अलगाव सिद्धांत का मुझे ध्यान क्यों है। यह कुछ ऐसा नहीं है जिसे मैं विश्वास के रूप में महत्वपूर्ण मानता हूं। यह एक वास्तविक समस्या हल करता है।

तो जिस तरह से इसे लागू किया जाना चाहिए वह आपके लिए एक समस्या को हल करना चाहिए। ISP को लागू करने के लिए कोई ब्रेन डेड रॉट तरीका नहीं है जिसे एक आवश्यक बदलाव के सही उदाहरण के साथ हराया नहीं जा सकता है। आपको यह देखना है कि सिस्टम कैसे बदल रहा है और विकल्प बनाएं जो चीजों को शांत कर देगा। चलिए विकल्प तलाशते हैं।

पहले खुद से पूछें: अभी सर्विस इंटरफ़ेस में बदलाव करना मुश्किल है? यदि नहीं, तो बाहर जाओ और तब तक खेलो जब तक तुम शांत न हो जाओ। यह एक बौद्धिक अभ्यास नहीं है। कृपया सुनिश्चित करें कि इलाज बीमारी से बदतर नहीं है।

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

  2.  

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

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

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

तो यह पता चला कि वे वास्तव में बहुत छोटे हो सकते हैं।

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


एक और अनुत्तरित प्रश्न है:

इन इंटरफेस का मालिक कौन है?

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

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

इंटरफ़ेस डिज़ाइन देखने के दो सरल तरीके यहां दिए गए हैं:

  • सेवा स्वामित्व वाला इंटरफ़ेस। कुछ लोग हर इंटरफ़ेस को डिजाइन कर सकते हैं जो एक सेवा कर सकती है। तुम भी IDE में refactoring विकल्प मिल सकता है कि आप जो भी वर्ग इसे खिलाने का उपयोग करते हुए आपके लिए एक इंटरफ़ेस लिखेंगे।

  • ग्राहक स्वामित्व वाला इंटरफ़ेस। आईएसपी का तर्क है कि यह सही है और स्वामित्व वाली सेवा गलत है। आपको ग्राहकों की जरूरतों को ध्यान में रखते हुए हर इंटरफेस को तोड़ना चाहिए। चूंकि क्लाइंट इंटरफ़ेस का मालिक है इसलिए इसे इसे परिभाषित करना चाहिए।

तो कौन सही है?

प्लगइन्स पर विचार करें:

यहाँ छवि विवरण दर्ज करें

यहाँ इंटरफेस का मालिक कौन है? ग्राहकों? सेवाएं?

दोनों को बाहर कर दिया।

यहां के रंग परतदार हैं। लाल परत (दाएं) को हरी परत (बाएं) के बारे में कुछ भी पता नहीं है। लाल परत को छुए बिना हरे रंग की परत को बदला या बदला जा सकता है। इस तरह किसी भी हरे रंग की परत को लाल परत में प्लग किया जा सकता है।

मुझे यह जानना पसंद है कि क्या जानना चाहिए और क्या नहीं जानना चाहिए। मेरे लिए, "क्या पता है?", सबसे महत्वपूर्ण वास्तुशिल्प प्रश्न है।

आइए कुछ शब्दावली स्पष्ट करें:

[Client] --> [Interface] <|-- [Service]

----- Flow ----- of ----- control ---->

एक क्लाइंट एक ऐसी चीज है जो उपयोग करता है।

एक सेवा एक ऐसी चीज है जिसका उपयोग किया जाता है।

Interactor दोनों होता है।

आईएसपी का कहना है कि ग्राहकों के लिए इंटरफेस को तोड़ना। ठीक है, इसे यहाँ लागू करें:

  • Presenter(एक सेवा) Output Port <I>इंटरफ़ेस को निर्देशित नहीं करना चाहिए । इंटरफ़ेस को Interactorयहां संकुचित किया जाना चाहिए कि (ग्राहक के रूप में कार्य करने के लिए) क्या चाहिए। इसका मतलब है कि InteractorISP का अनुसरण करने के लिए, इसके बारे में इंटरफ़ेस पता है , इसके साथ बदलना होगा। और यह ठीक है।

  • Interactor(यहां एक सेवा के रूप में कार्य करना) Input Port <I>इंटरफ़ेस को निर्देशित नहीं करना चाहिए । इंटरफ़ेस क्या Controller(एक ग्राहक) की जरूरत के लिए संकुचित किया जाना चाहिए । इसका मतलब है कि ControllerISP का अनुसरण करने के लिए, इसके बारे में इंटरफ़ेस पता है , इसके साथ बदलना होगा। और यह ठीक नहीं है।

दूसरी परत ठीक नहीं है क्योंकि लाल परत को हरी परत के बारे में पता नहीं है। तो क्या ISP गलत है? हाँ उस जैसा। कोई सिद्धांत निरपेक्ष नहीं है। यह एक ऐसा मामला है, जहां सेवा को सब कुछ दिखाने के लिए इंटरफ़ेस पसंद करने वाले नासमझ सही हो सकते हैं।

कम से कम, वे सही हैं अगर Interactorइस उपयोग के मामले की जरूरत के अलावा कुछ नहीं करता है। यदि Interactorअन्य उपयोग के मामलों के लिए चीजें होती हैं तो कोई कारण नहीं Input Port <I>है कि उनके बारे में यह पता चले। सुनिश्चित नहीं हैं कि Interactorकेवल एक उपयोग के मामले पर ध्यान केंद्रित क्यों नहीं किया जा सकता है, इसलिए यह एक गैर मुद्दा है, लेकिन सामान होता है।

लेकिन input port <I>इंटरफ़ेस बस Controllerग्राहक को गुलाम नहीं कर सकता है और यह एक सच्चा प्लगइन है। यह एक 'पुस्तकालय' सीमा है। एक पूरी तरह से अलग प्रोग्रामिंग शॉप लाल परत के प्रकाशित होने के बाद हरे रंग की परत के वर्षों को लिख सकती है।

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

एक तरीका है कि बंद एक अनुकूलक है। इसे क्लाइंट Controlerऔर Input Port <I>इंटरफ़ेस के बीच रखें । एडेप्टर Interactorएक के रूप में स्वीकार करता है Input Port <I>और प्रतिनिधियों को यह काम करता है। हालाँकि, यह केवल उसी ग्राहक को उजागर करता है जिसे Controllerरोल इंटरफ़ेस या ग्रीन लेयर के स्वामित्व वाले इंटरफेस के माध्यम से आवश्यकता होती है। एडेप्टर स्वयं ISP का पालन नहीं करता है, लेकिन अधिक जटिल वर्ग Controllerको ISP का आनंद लेने की अनुमति देता है । यह उपयोगी है अगर वहाँ ग्राहकों की तुलना में कम एडेप्टर हैं Controllerजो उनका उपयोग करते हैं और जब आप असामान्य स्थिति में होते हैं जहां आप एक पुस्तकालय की सीमा पार कर रहे हैं और प्रकाशित होने के बावजूद, पुस्तकालय बदलना बंद नहीं करेगा। आप फ़ायरफ़ॉक्स देख रहे हैं। अब वे परिवर्तन केवल आपके एडेप्टर को तोड़ते हैं।

अच्छा तो इसका क्या मतलब है? इसका मतलब है कि ईमानदारी से आपने मुझे यह बताने के लिए पर्याप्त जानकारी नहीं दी है कि आपको क्या करना चाहिए। मुझे नहीं पता कि ISP का पालन नहीं करने से आपको कोई समस्या हो रही है। मुझे नहीं पता कि अगर यह खत्म हो जाता तो आपको और अधिक समस्याएँ नहीं होतीं।

मुझे पता है कि आप एक सरल मार्गदर्शक सिद्धांत की तलाश कर रहे हैं। ISP बनने की कोशिश करता है। लेकिन यह बहुत कुछ नहीं छोड़ता है। मैं उसमे विश्वास करता हूँ। हां, कृपया ग्राहकों को उन तरीकों पर निर्भर होने के लिए मजबूर न करें, जिनका वे उपयोग नहीं करते हैं, बिना अच्छे कारण के!

यदि आपके पास एक अच्छा कारण है, जैसे कि आपके डिजाइनिंग प्लगइन्स को स्वीकार करने के लिए कुछ है, तो आईएसपी कारणों का पालन नहीं करने वाली समस्याओं के बारे में जागरूक रहें (यह ग्राहकों को तोड़ने के बिना बदलना मुश्किल है), और उन्हें कम करने के तरीके (रखें Interactorया कम से कम Input Port <I>एक स्थिर पर ध्यान केंद्रित करें) उदाहरण)।


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

मैं अब अपने पूर्ण नाम स्थान की तरह एक मोटी इंटरफ़ेस प्रदान करने वाली सेवा की ओर झुक रहा हूं, और यह क्लाइंट के लिए ग्राहक के विशिष्ट एडेप्टर के माध्यम से इन सेवाओं का उपयोग करना है। C शब्दों में, जो क्लाइंट के स्वामित्व वाले फ़ंक्शन रैपर की एक फ़ाइल होगी। सेवा में परिवर्तन करने से एडॉप्टर के पुनर्संयोजन को बल मिलेगा, लेकिन जरूरी नहीं कि क्लाइंट। .. <contd>
work.bin

<कंट> (प्रोग्रामर की) एडेप्टर को बनाए रखने में।
काम.बीन

मेरा वर्तमान समाधान मेरी आवश्यकताओं को संतुष्ट करता है, नया दृष्टिकोण अधिक प्रयास करेगा और अच्छी तरह से YAGNI का उल्लंघन कर सकता है। मुझे प्रत्येक विधि के पेशेवरों और विपक्षों का वजन करना होगा और यह तय करना होगा कि यहां किस रास्ते पर जाना है।
काम.बीन ११'१

1

तो यह बिंदु:

existent clients are unaffected by the addition (or deletion) of more clients.

यह बताता है कि आप एक अन्य महत्वपूर्ण सिद्धांत का उल्लंघन कर रहे हैं जो कि YAGNI है। मुझे इसकी परवाह तब होगी जब मेरे सैकड़ों ग्राहक होंगे। कुछ आगे के बारे में सोचकर फिर यह पता चलेगा कि आपके पास इस कोड के लिए कोई अतिरिक्त ग्राहक नहीं है।

दूसरा

 partitioning depends on the nature of clients

आपका कोड DI, निर्भरता व्युत्क्रम का उपयोग क्यों नहीं कर रहा है, कुछ भी नहीं, आपके पुस्तकालय में कुछ भी आपके ग्राहक की प्रकृति पर निर्भर नहीं होना चाहिए।

अंततः ऐसा लगता है कि आपको अतिव्यापी सामान के लिए आवश्यकताओं की पूर्ति के लिए अपने कोड के तहत अतिरिक्त परत की आवश्यकता है (DI इसलिए आपका फ्रंट फेसिंग कोड केवल इस अतिरिक्त परत पर निर्भर करता है, और आपके क्लाइंट केवल आपके सामने वाले इंटरफ़ेस पर निर्भर करते हैं) इस तरह से आप DRY को हरा देते हैं।
यह आप इसे वास्तविक के लिए छोटा करेंगे। तो आप वही सामान बनाते हैं जो आप दूसरे मॉड्यूल के नीचे योर मॉड्यूल लेयर में उपयोग करते हैं। इस तरह से नीचे परत आप प्राप्त करते हैं:

किसी भी ग्राहक के लिए केवल डेटा और API की आवश्यकता होती है जो दिखाई देता है; मॉड्यूल के बाकी नामस्थान क्लाइंट से छिपे हुए हैं अर्थात इंटरफ़ेस सेग्रीगेशन सिद्धांत का पालन करते हैं।

हाँ

एक घोषणा को कई हेडर फ़ाइलों में दोहराया नहीं जाता है अर्थात DRY का उल्लंघन नहीं होता है। मॉड्यूल M का अपने ग्राहकों पर कोई निर्भरता नहीं है।

हाँ

एक क्लाइंट मॉड्यूल M के कुछ हिस्सों में किए गए परिवर्तनों से अप्रभावित है जो इसका उपयोग नहीं करते हैं।

हाँ

मौजूदा क्लाइंट अधिक क्लाइंट्स को जोड़ने (या हटाने) से अप्रभावित रहते हैं।

हाँ


1

घोषणा में प्रदान की गई वही जानकारी हमेशा परिभाषा में दोहराई जाती है। यह इस भाषा के काम करने का तरीका है। इसके अलावा, कई हेडर फ़ाइलों में घोषणा को दोहराने से DRY का उल्लंघन नहीं होता है । यह आमतौर पर इस्तेमाल की जाने वाली तकनीक है (मानक पुस्तकालय में कम से कम)।

प्रलेखन को दोहराते हुए या कार्यान्वयन DRY का उल्लंघन होगा

जब तक क्लाइंट कोड मेरे द्वारा नहीं लिखा जाएगा, मैं खुद को इससे परेशान नहीं करूंगा।


0

मैं अपने भ्रम को दूर करता हूं। हालाँकि आपका व्यावहारिक उदाहरण मेरे सिर में एक समाधान निकालता है। अगर मैं अपने शब्दों में कहूं Mतो : मॉड्यूल में सभी विभाजन किसी भी और सभी ग्राहकों के साथ कई कई विशिष्ट संबंध हैं।

नमूना संरचना

M.h      // fat header
 - P1    // Partition 1
 - P2    // ... 2
   - P21 // ... 2 section 1
 - P3    // ... 3
C1.c     // Client 1 (Needs to include P1, P3)
C2.c     // ... 2 (Needs to include P2)
C3.c     // ... 3 (Needs to include P1, P21, P3)

MH

#ifdef P1
#define _PREF_ P1_             // Define Prefix ("PREF") = P1_
 void _PREF_init();            // Some partition specific function
#endif /* P1 */

#ifdef P2
#define _PREF_ P2_
 void _PREF_init();
#endif /* P2 */

#if defined(P21) || defined (P2) // Part 2.1
#define _PREF_ P2_1_
 void _PREF_oddone();
#endif /* P21 */

#ifdef P3
#define _PREF_ P3_
 void _PREF_init();
#endif /* P3 */

Mc

Mc फ़ाइल में, आपको वास्तव में #ifdefs का उपयोग नहीं करना होगा क्योंकि आपने जो .c फ़ाइल में रखा है, वह क्लाइंट फ़ाइलों को तब तक प्रभावित नहीं करती है, जब तक कि क्लाइंट फ़ाइलों का उपयोग परिभाषित न हो जाए।

#include "M.h"
#define _PREF_ P1_        
void _PREF_init() { ... };

#define _PREF_ P2_
void _PREF_init() { ... }

#define _PREF_ P2_1_
void _PREF_oddone() { ... }

#define _PREF_ P3_
void _PREF_init() { ... }

C1.c

#define P1     // "invite" P1
#define P3     // "invite" P3
#include "M.h" // Open the door, but only the invited come in.

void main()
{
    P1_init();
    //P2_init();
    //P2_1_oddone();
    P3_init();
}

C2.c

#define P2
#include "M.h

void main()
{
    //P1_init();
    P2_init();
    P2_1_oddone();
    //P3_init();
}

C3.c

#define P1
#define P21
#define P3  
#include "M.h" 

void main()
{
    P1_init();
    //P2_init();
    P2_1_oddone();
    P3_init();
}

फिर, मुझे यकीन नहीं है कि यह वही है जो आप पूछ रहे हैं। इसलिए इसे नमक के दाने के साथ लें।


मैक कैसा दिखता है? क्या आप परिभाषित करते हैं P1_init() और P2_init() ?
काम.बीन ११'१

@ work.bin मैं अनुमान लगाता हूं कि मैक एक सरल .c फ़ाइल की तरह होगा, जिसमें फ़ंक्शन के बीच नाम स्थान को परिभाषित करने के अपवाद होंगे।
सांचे देलारर

मान लें कि C1 और C2 दोनों मौजूद हैं - क्या करता है P1_init()और क्या P2_init()लिंक करता है?
.बीन

Mh / Mc फ़ाइल में, प्रीप्रोसेसर _PREF_जो कुछ भी अंतिम रूप से परिभाषित किया गया था , उसकी जगह लेगा । तो आखिरी # बयान के कारण _PREF_init()होगा P1_init()। फिर अगला परिभाषित कथन PREF को P2_ के बराबर सेट करेगा , इस प्रकार जनरेट करेगा P2_init()
सांचके दलोदर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.