2010-09-27 13 views
8

मैं कुछ महीने पहले कोड का एक गुच्छा लिख ​​रहा था और अब मैं इसमें सामान जोड़ रहा हूं। मुझे एहसास हुआ कि मैंने उन कार्यों का एक समूह लिखा है जो एक वर्ग से निकलती हैं जिसमें इसके कार्यों के लगभग 2/3s सार और शेष 1/3 वर्चुअल हैं।डेल्फी: रखरखाव वर्चुअल बनाम आभासी सार

मैं बहुत ज्यादा देखने के बीमार हूँ:

function descendent.doSomething() : TList; 
begin 
    inherited; 
end; 

जब मैं आधार वर्ग के लिए यह मिल गया है:

function descendent.doSomething() : TList; 
begin 
    result := nil; 
end; 

और साथ हवा नहीं चाहते:

function descendent.doSomething() : TList; 
begin 

end; 

और फिर आश्चर्य की बात क्यों कुछ काम नहीं किया।

मुझे सार कार्यों का उपयोग करना पसंद है क्योंकि संकलक आपको बताएगा कि क्या आप एक अमूर्त त्रुटि प्राप्त करने के लिए उत्तरदायी हैं क्योंकि आपने कुछ कार्यों को लागू नहीं किया है।

मेरा प्रश्न है, क्योंकि मैं अभी भी अपेक्षाकृत नया डेल्फी प्रोग्रामर हूं और मुझे कभी भी 8 साल तक कुछ भी बनाए रखना नहीं है, इसलिए इस समय prune your code पर समय लेना उचित है (यानी उन कार्यों को हटाएं जो अभी विरासत में हैं उनमें और अपने बेस क्लास फ़ंक्शंस को अमूर्त से कंक्रीट में बदलें)

उत्तर

1

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

+0

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

7

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

IAllInterfaced = interface(IInterface) 
    procedure ImplementMeEverywhere_1(const Params: TParams); 
    procedure ImplementMeEverywhere_2(const Params: TParams); 
    procedure ImplementMeEverywhere_3(const Params: TParams); 
    end; 

    TAllInterfaced_ClassA = class(TInterfacedObject, IAllInterfaced) 
    public 
    procedure ImplementMeEverywhere_1(const Params: TParams); 
    procedure ImplementMeEverywhere_2(const Params: TParams); 
    procedure ImplementMeEverywhere_3(const Params: TParams); 
    end; 

    TAllInterfaced_ClassB = class(TInterfacedObject, IAllInterfaced) 
    public 
    procedure ImplementMeEverywhere_1(const Params: TParams); 
    procedure ImplementMeEverywhere_2(const Params: TParams); 
    procedure ImplementMeEverywhere_3(const Params: TParams); 
    end; 

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

दूसरा विकल्प है:

IAllAbstract = interface(IInterface) 
    procedure ImplementMeEverywhere_1(const Params: TParams); 
    procedure ImplementMeEverywhere_2(const Params: TParams); 
    procedure ImplementMeEverywhere_3(const Params: TParams); 
    end; 

    TAllAbstract_Custom = (TInterfacedObject, IAllAbstract) 
    private 
    ... 
    public 
    procedure ImplementMeEverywhere_1(const Params: TParams); virtual; abstract; 
    procedure ImplementMeEverywhere_2(const Params: TParams); virtual; abstract; 
    procedure ImplementMeEverywhere_3(const Params: TParams); virtual; abstract; 
    end; 

    TAllAbstract_ClassA = class(TAllAbstract_Custom) 
    public 
    procedure ImplementMeEverywhere_1(const Params: TParams); override; 
    procedure ImplementMeEverywhere_2(const Params: TParams); override; 
    procedure ImplementMeEverywhere_3(const Params: TParams); override; 
    end; 

    TAllAbstract_ClassB = class(TAllAbstract_Custom) 
    public 
    procedure ImplementMeEverywhere_1(const Params: TParams); override; 
    procedure ImplementMeEverywhere_2(const Params: TParams); override; 
    procedure ImplementMeEverywhere_3(const Params: TParams); override; 
    end; 

यहाँ आप सभी वर्गों के लिए एक आधार वर्ग की है। उस वर्ग में आपके पास सामान्य गुण या घटना अन्य कक्षाएं आदि हो सकती हैं ... लेकिन सभी प्रक्रियाओं को सार के रूप में चिह्नित किया जाता है क्योंकि वे कोई सामान्य कार्य नहीं करते हैं। सार सुनिश्चित करता है कि वे व्युत्पन्न कक्षाओं में लागू किए जाएंगे, लेकिन आपको प्रत्येक कक्षा में "फ़ील्डए" को लागू करने की आवश्यकता नहीं है, आप इसे केवल "TAllAbstract_Custom" में कार्यान्वित करते हैं। यह सुनिश्चित करता है कि DRY सिद्धांत का उपयोग किया जाता है।

अंतिम विकल्प है:

IAllVirtual = interface(IInterface) 
    procedure ImplementMeEverywhere_1(const Params: TParams); 
    procedure ImplementMeEverywhere_2(const Params: TParams); 
    procedure ImplementMeEverywhere_3(const Params: TParams); 
    end; 

    TAllVirtual_Custom = (TInterfacedObject, IAllVirtual) 
    private 
    ... 
    public 
    procedure ImplementMeEverywhere_1(const Params: TParams); virtual; 
    procedure ImplementMeEverywhere_2(const Params: TParams); virtual; 
    procedure ImplementMeEverywhere_3(const Params: TParams); virtual; 
    end; 

    TAllVirtual_ClassA = class(TAllVirtual_Custom) 
    public 
    procedure ImplementMeEverywhere_1(const Params: TParams); override; 
    procedure ImplementMeEverywhere_2(const Params: TParams); override; 
    procedure ImplementMeEverywhere_3(const Params: TParams); override; 
    end; 

    TAllVirtual_ClassB = class(TAllVirtual_Custom) 
    public 
    procedure ImplementMeEverywhere_1(const Params: TParams); override; 
    procedure ImplementMeEverywhere_2(const Params: TParams); override; 
    procedure ImplementMeEverywhere_3(const Params: TParams); override; 
    end; 

यहाँ सब व्युत्पन्न वर्ग एक आम आधार आभासी प्रक्रिया है। यह सुनिश्चित करता है कि आपको व्युत्पन्न कक्षाओं के स्तर पर प्रत्येक प्रक्रिया को लागू करने की आवश्यकता नहीं है। आप केवल कोड के कुछ हिस्सों को ओवरराइड कर सकते हैं या कोई भी नहीं।

स्वाभाविक रूप से यह सभी किनारे के मामले हैं, उनमें बीटवेन में कमरा है। आप उन अवधारणाओं का मिश्रण कर सकते हैं।

बस इतना ध्यान रखें:

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

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

1

हां, अपना कोड छीनें।

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

संबंधित मुद्दे