यह समझने की कुंजी यह जानना है कि यह परिभाषा बनाम से अधिक है।कार्यान्वयन। यह वही संज्ञा का वर्णन करने के विभिन्न तरीके के बारे में बताया गया है:
- कक्षा विरासत सवाल का जवाब: "इस वस्तु किस तरह का है"
- इंटरफ़ेस कार्यान्वयन प्रश्न का उत्तर दें: "मैं इस ऑब्जेक्ट के साथ क्या कर सकता हूं?"
मान लीजिए कि आप एक रसोई मॉडलिंग कर रहे हैं। (निम्नलिखित खाद्य अनुरूपताओं के लिए अग्रिम में माफ़ी, मैं बस दोपहर के भोजन से वापस आ गया ...) आपके पास तीन मूल प्रकार के बर्तन हैं - कांटे, चाकू और चम्मच। ये सभी बर्तन श्रेणी के अंतर्गत फिट है, तो हम उस मॉडल होगा (मैं समर्थन क्षेत्रों की तरह उबाऊ सामान में से कुछ को छोड़ते हुए कर रहा हूँ):
type
TMaterial = (mtPlastic, mtSteel, mtSilver);
TUtensil = class
public
function GetWeight : Integer; virtual; abstract;
procedure Wash; virtual; // Yes, it's self-cleaning
published
property Material : TMaterial read FMaterial write FMaterial;
end;
यह सब किसी भी बर्तन करने के लिए डेटा और कार्यक्षमता आम का वर्णन करता है - क्या यह बना है, इसका वजन क्या है (जो ठोस प्रकार पर निर्भर करता है), लेकिन आप देखेंगे कि अमूर्त वर्ग वास्तव में कुछ भी नहीं करता है। TFork
और TKnife
वास्तव में अधिक सामान्य नहीं है कि आप बेस क्लास में डाल सकते हैं। आप तकनीकी रूप से Cut
TFork
के साथ कर सकते हैं, लेकिन TSpoon
एक खिंचाव हो सकता है, तो इस तथ्य को कैसे प्रतिबिंबित किया जाए कि केवल कुछ बर्तन कुछ चीजें कर सकते हैं?
ठीक है, हम पदानुक्रम का विस्तार शुरू कर सकते हैं, लेकिन यह गंदा हो जाता है:
type
TSharpUtensil = class
public
procedure Cut(food : TFood); virtual; abstract;
end;
कि तेज लोगों का ख्याल रखता है, लेकिन अगर हम समूह के बजाय इस तरह से करना चाहते हैं?
type
TLiftingUtensil = class
public
procedure Lift(food : TFood); virtual; abstract;
end;
TFork
और TKnife
दोनों TSharpUtensil
के तहत फिट होगा, लेकिन TKnife
चिकन का एक टुकड़ा ऊपर उठाने के लिए बहुत घटिया है। हम या तो इन पदानुक्रमों में से किसी एक को चुनने के लिए समाप्त होते हैं, या इस कार्यक्षमता को सामान्य TUtensil
में फेंक देते हैं और कक्षाएं प्राप्त कर चुके हैं जो विधियों को लागू करने से इनकार करते हैं। डिजाइन के लिहाज से, यह एक ऐसी स्थिति है कि हम खुद में अटक गया। पता लगाना चाहते हैं नहीं है
बेशक
इस के साथ वास्तविक समस्या यह है कि हम विरासत का उपयोग कर रहे वर्णन करने के लिए क्या एक वस्तु करता है, न कि इसमें क्या है। पूर्व के लिए, हमारे पास इंटरफेस हैं। हम इस डिज़ाइन को एक बहुत साफ कर सकते हैं:
type
IPointy = interface
procedure Pierce(food : TFood);
end;
IScoop = interface
procedure Scoop(food : TFood);
end;
अब हम सुलझा सकते हैं ठोस प्रकार क्या करना:
type
TFork = class(TUtensil, IPointy, IScoop)
...
end;
TKnife = class(TUtensil, IPointy)
...
end;
TSpoon = class(TUtensil, IScoop)
...
end;
TSkewer = class(TStick, IPointy)
...
end;
TShovel = class(TGardenTool, IScoop)
...
end;
मैं सबके विचार हो जाता है लगता है। बिंदु (कोई इरादा नहीं है) यह है कि हमारी पूरी प्रक्रिया पर बहुत अच्छा नियंत्रण है, और हमें कोई ट्रेडऑफ नहीं करना है। हम दोनों विरासत और इंटरफ़ेस का उपयोग कर रहे हैं, विकल्प पारस्परिक रूप से अनन्य नहीं हैं, यह केवल इतना है कि हम केवल सार वर्ग में कार्यक्षमता शामिल करते हैं, वास्तव में, वास्तव में सामान्य सभी व्युत्पन्न प्रकारों में।
किया जाए या नहीं आप अमूर्त वर्ग या एक या इंटरफेस नीचे की ओर वास्तव में आप इसके साथ क्या करने की जरूरत पर निर्भर करता है अधिक का उपयोग करने के लिए चुन:,
type
TDishwasher = class
procedure Wash(utensils : Array of TUtensil);
end;
यह समझ में आता है क्योंकि केवल बर्तन में जाना डिशवॉशर, कम से कम हमारे सीमित रसोईघर में जिसमें व्यंजन या कप जैसी सुविधाएं शामिल नहीं हैं। TSkewer
और TShovel
शायद वहां नहीं जाते हैं, भले ही वे खाने की प्रक्रिया में तकनीकी रूप से भाग ले सकें।
दूसरी ओर:
type
THungryMan = class
procedure EatChicken(food : TFood; utensil : TUtensil);
end;
यह इतना अच्छा नहीं हो सकता है। वह सिर्फ TKnife
(अच्छी तरह से नहीं, आसानी से) के साथ नहीं खा सकता है। और TFork
और TKnife
दोनों की आवश्यकता नहीं है; क्या होगा यदि यह एक चिकन विंग है?
यह एक बहुत अधिक समझ में आता है:
type
THungryMan = class
procedure EatPudding(food : TFood; scoop : IScoop);
end;
अब हम उसे दे सकते हैं या तो TFork
, TSpoon
, या TShovel
, और वह खुश है, लेकिन नहीं TKnife
, जो अभी भी एक बर्तन है, लेकिन ऐसा नहीं करता वास्तव में यहां मदद करें।
आप यह भी देखेंगे कि दूसरा संस्करण वर्ग पदानुक्रम में परिवर्तनों के प्रति कम संवेदनशील है। यदि हम से प्राप्त होने के लिए TFork
को बदलने का निर्णय लेते हैं, तो हमारे आदमी अभी भी खुश हैं जब तक कि यह अभी भी IScoop
लागू करता है।
मैं भी एक तरह से यहां संदर्भ गिनती मुद्दे पर भुला दिया है, और मैं @Deltics यह सबसे अच्छा ने कहा कि लगता है; सिर्फ इसलिए कि आपके पास AddRef
है इसका मतलब यह नहीं है कि आपको उसी चीज़ को करने की आवश्यकता है जो TInterfacedObject
करता है। इंटरफेस संदर्भ-गिनती एक आकस्मिक विशेषता है, यह उस समय के लिए उपयोगी उपकरण है जब आपको इसकी आवश्यकता होती है, लेकिन यदि आप कक्षा अर्थशास्त्र (और अक्सर आप हैं) के साथ इंटरफेस मिश्रण करने जा रहे हैं, तो यह हमेशा नहीं होता है संदर्भ-गणना सुविधा का उपयोग स्मृति प्रबंधन के रूप में करने के लिए समझ में आता है।
असल में, मैं कहता हूं कि अधिकतर समय में, आप शायद संदर्भ गणना अर्थशास्त्र संदर्भ नहीं चाहते हैं। हाँ, वहां, मैंने यह कहा। मुझे हमेशा लगा कि पूरी रेफ-गिनती चीज सिर्फ ओएलई स्वचालन और ऐसे (IDispatch
) का समर्थन करने में मदद करने के लिए थी। जब तक आपके इंटरफ़ेस के स्वचालित विनाश को पाने का कोई अच्छा कारण न हो, तो बस इसके बारे में भूल जाएं, TInterfacedObject
का उपयोग न करें। जब आपको आवश्यकता हो तो आप इसे हमेशा बदल सकते हैं - यह एक इंटरफेस का उपयोग करने का मुद्दा है! स्मृति/आजीवन प्रबंधन के परिप्रेक्ष्य से नहीं, एक उच्च स्तरीय डिज़ाइन बिंदु दृश्य से इंटरफेस के बारे में सोचें।
तो कहानी का नैतिक है:
जब आप समर्थन कुछ विशेष कार्यक्षमता को एक वस्तु की आवश्यकता होती है, एक इंटरफेस का उपयोग करने का प्रयास करें।
जब वस्तुओं एक ही परिवार की रहे हैं और आप शेयर आम सुविधाओं करने के लिए उन्हें चाहते हैं, एक आम आधार वर्ग से विरासत।
और यदि दोनों स्थितियां लागू होती हैं, तो दोनों का उपयोग करें!
+1, बहुत अच्छा सवाल। – mghie
संबंधित प्रश्न: http://stackoverflow.com/questions/918380/abstract-classes-vs-interfaces-vs-mixins। डेल्फी के लिए विशिष्ट सवाल उचित लगता है। – mghie
मुझे अंतर पता है, लेकिन वास्तव में मुझे लगता है कि कुछ याद आ रही है :) शायद दोनों का समझौता? एक नई घोषणा के बारे में क्या: टीबीएस = अमूर्त वर्ग ... अंत; एक इंटरफेस की तरह अधिनियम, लेकिन संदर्भ गिनती के बिना। –