एक अमूर्त वर्ग पर इंटरफेस


30

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

interface IFooWorker { void Work(); }

abstract class BaseWorker {
    ... base class behaviors ...
    public abstract void Work() { }
    protected string CleanData(string data) { ... }
}

class DbWorker : BaseWorker, IFooWorker {
    public void Work() {
        Repository.AddCleanData(base.CleanData(UI.GetDirtyData()));
    }
}

DbWorker को IFooWorker इंटरफ़ेस मिलता है, क्योंकि यह इंटरफ़ेस का तात्कालिक कार्यान्वयन है। यह पूरी तरह से अनुबंध को पूरा करता है। मेरे सहकर्मी लगभग समान पसंद करते हैं:

interface IFooWorker { void Work(); }

abstract class BaseWorker : IFooWorker {
    ... base class behaviors ...
    public abstract void Work() { }
    protected string CleanData(string data) { ... }
}

class DbWorker : BaseWorker {
    public void Work() {
        Repository.AddCleanData(base.CleanData(UI.GetDirtyData()));
    }
}

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

उसकी विधि बनाम खान के पक्ष और विपक्ष क्या हैं, और एक का दूसरे पर इस्तेमाल क्यों किया जाना चाहिए?


आपका सुझाव बहुत बारीकी से हीरे की विरासत से मिलता जुलता है , जिसके कारण बहुत अधिक भ्रम की स्थिति पैदा हो सकती है।
स्पोइक

@ साइकाइक: कैसे देखें?
14

@ टिप्पणी में मैंने जो लिंक दिया है, उसमें एक साधारण वर्ग आरेख और एक सादा लाइनर स्पष्टीकरण है जो कि है। इसकी "डायमंड" समस्या कहा जाता है क्योंकि वंशानुक्रम संरचना मूल रूप से हीरे के आकार (यानी "") की तरह खींची जाती है।
Spoike

@ साइकाइक: क्यों इस सवाल के कारण हीरे की विरासत होगी?
निइंग

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

जवाबों:


24

मेरा यह मानना ​​है कि एक वर्ग को एक इंटरफ़ेस लागू नहीं करना चाहिए जब तक कि उस वर्ग का उपयोग तब नहीं किया जा सकता जब इंटरफ़ेस का कार्यान्वयन आवश्यक हो।

BaseWorkerउस आवश्यकता को पूरा करता है। सिर्फ इसलिए कि आप सीधे किसी BaseWorkerवस्तु को तुरंत नहीं दे सकते इसका मतलब यह नहीं है कि आपके पास अनुबंध को पूरा करने वाला एक BaseWorker सूचक नहीं हो सकता है । वास्तव में, यह बहुत सार वर्गों के पूरे बिंदु है।

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

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


1
+1 यह इंगित करने के लिए कि सिर्फ इसलिए BaseWorkerकि यह तत्काल नहीं है, इसका मतलब यह नहीं है कि कोई भी BaseWorker myWorkerलागू नहीं करता है IFooWorker
अवनेर शाहर-कश्तन

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

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

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

46

मुझे आपके सहकर्मी से सहमत होना होगा।

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

यदि आप BaseWorker की एक विधि के रूप में कार्य () को परिभाषित नहीं कर रहे थे, या यदि IFooWorker के पास अन्य विधियाँ थीं, जो BaseWorker के उप-वर्ग नहीं चाहते या आवश्यकता नहीं होगी, तो (स्पष्ट रूप से) आपको यह इंगित करना होगा कि कौन-से उप-वर्ग वास्तव में IFooWorker को लागू कर सकते हैं।


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

2
मैं आम तौर पर सहमत हूं, लेकिन यह बताना चाहूंगा कि "आधार", "मानक", "डिफ़ॉल्ट", "सामान्य", आदि जैसे शब्द एक वर्ग नाम में कोड गंध हैं। यदि एक सार आधार वर्ग का इंटरफ़ेस के रूप में लगभग एक ही नाम है, लेकिन उन में से एक शब्द शामिल हैं, तो यह अक्सर गलत अमूर्तता का संकेत है; इंटरफेस परिभाषित करता है कि कुछ क्या करता है , टाइप इनहेरिटेंस परिभाषित करता है कि यह क्या है । यदि आपके पास एक है IFooऔर BaseFooतब इसका तात्पर्य है कि या तो IFooउचित रूप से ठीक-ठीक इंटरफ़ेस नहीं है, या वह BaseFooवंशानुक्रम का उपयोग कर रहा है जहां रचना एक बेहतर विकल्प हो सकती है।
हारून

@Aaronaught Good point, हालाँकि यह हो सकता है कि वास्तव में ऐसा कुछ है जो IFoo के सभी या अधिकांश कार्यान्वयनों को विरासत में प्राप्त करने की आवश्यकता है (जैसे कि एक सेवा या अपने DAO कार्यान्वयन के लिए एक संभाल)।
मैथ्यू फ्लिन

2
तब आधार वर्ग नहीं बुलाया जाना चाहिए MyDaoFooया SqlFooया HibernateFooया जो कुछ भी संकेत मिलता है कि यह सिर्फ एक को लागू करने वर्गों में से संभव पेड़ है IFoo? अगर किसी बेस क्लास को किसी विशिष्ट लाइब्रेरी या प्लेटफ़ॉर्म पर जोड़ा जाए तो मेरे लिए यह और भी अधिक बदबूदार होता है और नाम में इसका कोई उल्लेख नहीं है ...
Aaronaught

@Aaronaught - हाँ। मैं पूरी तरह से सहमत हूँ।
मैथ्यू फ्लिन

11

मैं आमतौर पर आपके सहकर्मी से सहमत हूं।

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

यह अतिरिक्त रूप से आपके पदानुक्रम को अस्पष्ट बनाता है; "सभी IFooWorkers BaseWorkers हैं" आवश्यक रूप से एक सही कथन नहीं है, और न ही "All BaseWorkers IFooWorkers हैं"। इसलिए, यदि आप एक उदाहरण चर, पैरामीटर, या रिटर्न प्रकार को परिभाषित करना चाहते हैं, जो कि IFooWorker या BaseWorker (आम उजागर कार्यक्षमता का लाभ उठा सकता है, जो किसी भी तरह से लागू हो सकता है, जो पहले स्थान पर विरासत में से एक है), न तो इन सभी को शामिल किए जाने की गारंटी है; कुछ BaseWorkers IFooWorker के एक वेरिएबल के लिए असाइन नहीं किए जाएंगे, और इसके विपरीत।

आपके सहकर्मी के मॉडल का उपयोग करना और प्रतिस्थापित करना बहुत आसान है। "सभी बेसवर्कर्स IFooWorkers हैं" अब एक सही कथन है; आप किसी भी IFooWorker निर्भरता, कोई समस्या नहीं के लिए किसी भी BaseWorker उदाहरण दे सकते हैं। विपरीत कथन "ऑल इफवूवेकर्स बेसवर्कर्स हैं" सच नहीं है; यह आपको BaseWorker को BetterBaseWorker से बदलने की अनुमति देता है और आपका उपभोग कोड (जो IFooWorker पर निर्भर करता है) को अंतर बताने की आवश्यकता नहीं होगी।


मुझे इस उत्तर की ध्वनि पसंद है लेकिन पिछले भाग का काफी अनुसरण नहीं करते हैं। आप सुझाव दे रहे हैं कि BetterBaseWorker एक स्वतंत्र अमूर्त वर्ग होगा जो IFooWorker को लागू करता है, ताकि मेरा काल्पनिक प्लगइन "ओह बॉय!" कह सके! बेहतर बेस वर्कर आखिरकार बाहर है। और किसी भी BaseWorker संदर्भ को BetterBaseWorker में बदल दें और इसे एक दिन कहें (हो सकता है कि शांत नए लौटे मूल्यों के साथ खेलें जो मुझे अपने अनावश्यक कोड के विशाल हिस्से को बाहर निकालने दें)?
एंथोनी

कमोबेश, हाँ। बड़ा फायदा यह है कि आप बेसवर्कर के संदर्भों की संख्या को कम कर देंगे, जिन्हें इसके बजाय बेटरबेसवर्कर्स होने के लिए बदलना होगा; आपके अधिकांश कोड IFooWorker का उपयोग करने के बजाय, सीधे ठोस वर्ग को संदर्भित नहीं करेंगे, इसलिए जब आप उन IFooWorker निर्भरता (वर्गों, गुणकों या विधियों के गुणों) को असाइन किए गए कोड को बदलते हैं, तो IFooWorker का उपयोग करने वाले कोड को कोई अंतर दिखाई देगा। उपयोग में।
कीथ

6

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

जावा की संग्रह रूपरेखा कक्षाएं लें:

abstract class AbstractList
class LinkedList extends AbstractList implements Queue

तथ्य यह है कि क्यू अनुबंध अनुबंध लिंक्डलिस्ट द्वारा कार्यान्वित किया गया है ने एब्स्ट्रैक्टलिस्ट में चिंता को धक्का नहीं दिया ।

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


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

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

1
मुझे चेतावनी मिलती है, लेकिन आप ध्यान देंगे कि ओपी के सार वर्ग में इंटरफ़ेस से मेल खाने वाली सार विधियाँ शामिल हैं: एक बेसवर्कर का अर्थ एक IFooWorker है। इसे स्पष्ट करना इस तथ्य को और अधिक उपयोगी बनाता है। क्यू में शामिल कई विधियाँ, जो कि एब्सट्रेलिस्ट में शामिल नहीं हैं, हालाँकि, और इस तरह, एब्सट्रेलिस्ट एक क्यू नहीं है, भले ही उसके बच्चे हों। AbstractList और क्यू ऑर्थोगोनल हैं।
मैथ्यू फ्लिन

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

डांग, छह साल हो गए। :)
मिहाई दानीला

2

मैं सवाल पूछूंगा कि जब आप बदलते हैं तो क्या होता है IFooWorker, जैसे कि एक नया तरीका?

यदि BaseWorkerइंटरफ़ेस को लागू करता है, तो डिफ़ॉल्ट रूप से उसे नई पद्धति घोषित करनी होगी, भले ही वह अमूर्त हो। दूसरी ओर, यदि यह इंटरफ़ेस लागू नहीं करता है, तो आपको केवल व्युत्पन्न वर्गों पर संकलन त्रुटियां मिलेंगी।

इस कारण से, मैं बेस क्लास को इंटरफ़ेस लागू करूंगा, क्योंकि मैं व्युत्पन्न वर्गों को छुए बिना बेस क्लास में नई पद्धति के लिए सभी कार्यक्षमता को लागू करने में सक्षम हो सकता हूं ।


1

पहले सोचें कि एक सार आधार वर्ग क्या है, और एक इंटरफ़ेस क्या है। विचार करें कि आप एक या दूसरे का उपयोग कब करेंगे और कब नहीं करेंगे।

लोगों के लिए दोनों का विचार समान विचारधारा वाला होना आम है, वास्तव में यह एक सामान्य साक्षात्कार प्रश्न है (दोनों में अंतर है ??)

इसलिए एक सार आधार वर्ग आपको कुछ इंटरफेस देता है जो कि तरीकों का डिफ़ॉल्ट कार्यान्वयन नहीं है। (अन्य सामान है, सी # में आप एक सार वर्ग पर स्थिर तरीके रख सकते हैं, उदाहरण के लिए इंटरफ़ेस पर नहीं)।

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

इसलिए किसी भी समय सभी व्युत्पन्न वर्गों को इंटरफ़ेस का समर्थन करने की आवश्यकता होती है, यह आधार वर्ग पर जाता है। यदि केवल एक या कुछ को उस इंटरफ़ेस की आवश्यकता होती है, तो यह व्युत्पन्न वर्ग पर जाएगा।

यह सब वास्तव में सरलीकरण पर एक सकल है। एक अन्य विकल्प यह है कि व्युत्पन्न वर्ग भी इंटरफेस को लागू नहीं करते हैं, लेकिन उन्हें एक एडाप्टर पैटर्न के माध्यम से प्रदान करते हैं। इसका एक उदाहरण मैंने हाल ही में देखा IObjectContextAdapter में था।


1

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

प्रथम:

एक इंटरफ़ेस के दो सामान्य स्पष्टीकरण हैं:

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

  2. इंटरफेस अमूर्त वर्ग हैं जो कुछ भी नहीं / नहीं कर सकते हैं। वे उपयोगी हैं क्योंकि आप उन माध्य वर्गों के विपरीत एक से अधिक कार्यान्वित कर सकते हैं। जैसे, मैं क्लास बनानाब्रेड का एक ऑब्जेक्ट हो सकता हूं, और बेसब्रैड से विरासत में मिल सकता है, लेकिन इसका मतलब यह नहीं है कि मैं IWithNuts और IT स्वादYummy इंटरफेस दोनों को लागू नहीं कर सकता। मैं भी IDoesTheDishes इंटरफ़ेस को लागू कर सकता था, क्योंकि मैं सिर्फ रोटी, yknow नहीं हूं?

एक अमूर्त वर्ग के दो सामान्य स्पष्टीकरण हैं:

  1. एक अमूर्त वर्ग है, yknow, वह चीज जो वह नहीं कर सकता है। यह पसंद है, सार, वास्तव में बिल्कुल वास्तविक चीज नहीं है। रुको, यह मदद करेगा। एक नाव एक सार वर्ग है, लेकिन एक सेक्सी प्लेबॉय यॉट बेसबोट का एक उप वर्ग होगा।

  2. मैं अमूर्त कक्षाओं में एक पुस्तक पढ़ता हूं, और शायद आपको वह पुस्तक पढ़नी चाहिए, क्योंकि आप शायद इसे प्राप्त नहीं करते हैं और यदि आप उस पुस्तक को नहीं पढ़ते हैं तो यह गलत होगा।

वैसे, सिटीज़ बुक हमेशा प्रभावशाली लगती है, भले ही मैं अभी भी उलझन में हूं।

दूसरा:

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

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

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

तीसरा:

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

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


0

जैसा कि आप सुझाव देते हैं, DbWorkerइसे लागू करने का एक और पहलू IFooWorkerहै।

अपने सहकर्मी की शैली के मामले में, यदि किसी कारण से बाद में रिफ्लेक्टरिंग होती है और DbWorkerयह माना जाता है कि अमूर्त BaseWorkerवर्ग का विस्तार नहीं किया जाता है , DbWorkerतो IFooWorkerइंटरफ़ेस खो देता है। ऐसा हो सकता है, लेकिन जरूरी नहीं कि इसका उपभोग करने वाले ग्राहकों पर असर पड़े, अगर वे IFooWorkerइंटरफेस की उम्मीद करते हैं ।


-1

शुरू करने के लिए, मैं इंटरफेस और अमूर्त वर्गों को अलग तरह से परिभाषित करना पसंद करता हूं:

Interface: a contract that each class must fulfill if they are to implement that interface
Abstract class: a general class (i.e vehicle is an abstract class, while porche911 is not)

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

अब, इंटरफ़ेस DbWorkerको संतुष्ट करता IFooWorkerहै, लेकिन अगर कोई विशिष्ट तरीका है जो यह वर्ग करता है work(), तो उसे वास्तव में विरासत में मिली परिभाषा को ओवरलोड करना होगा BaseWorker। इसका कारण यह IFooWorkerहै कि इंटरफ़ेस को सीधे लागू नहीं किया जाना चाहिए क्योंकि यह कुछ विशेष नहीं है DbWorker। यदि आपने ऐसा किया है कि हर बार आपने समान कक्षाएं लागू की हैं DbWorkerतो आप DRY का उल्लंघन करेंगे ।

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


-3

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


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

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

1
शायद आप इंटरफ़ेस में "वर्कर" शब्द पर अटक गए हैं। "डेटासोर्स" के बारे में क्या? यदि हमारे पास एक IDatasource <T> है, तो हम तुच्छ रूप से SqlDatasource <T>, RestDatasource <T>, MongoDatasource <T> कर सकते हैं। व्यवसाय तय करता है कि जेनेरिक इंटरफ़ेस के कौन से समापन अमूर्त डेटा स्रोत के समापन कार्यान्वयन पर जाते हैं।
ब्रायन बोएचर

यह डीआरवाई की खातिर विरासत का उपयोग करने के लिए समझदारी बना सकता है और कुछ सामान्य कार्यान्वयन को आधार वर्ग में रख सकता है। लेकिन आप किसी भी इंटरफ़ेस विधियों के साथ ओवरराइड विधियों को संरेखित नहीं करेंगे, बेस क्लास में सामान्य समर्थन तर्क होगा। यदि वे लाइन अप करते हैं, तो यह दिखाएगा कि वंशानुक्रम आपकी समस्या को ठीक करता है और इंटरफ़ेस बिना किसी उद्देश्य के काम करेगा। आप उन मामलों में एक इंटरफ़ेस का उपयोग करते हैं जो वंशानुक्रम आपकी समस्या का समाधान नहीं करते हैं क्योंकि आप जिन सामान्य विशेषताओं को मॉडल करना चाहते हैं, वे एकल वर्ग के पेड़ के अनुरूप नहीं हैं। और हाँ, उदाहरण में शब्दांकन इसे और अधिक गलत बनाता है।
मार्टिन मात
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.