2010-03-29 5 views
7

मेरे पास निम्न दो तरीकों कि (जैसा कि आप देख सकते हैं) एक को छोड़कर अपने बयान से ज्यादातर में समान हैं (विवरण के लिए नीचे देखें)Refactor दो सी ++ तरीकों का पालन डुप्लिकेट कोड बाहर स्थानांतरित करने के

unsigned int CSWX::getLineParameters(const SURFACE & surface, vector<double> & params) 
{ 
    VARIANT varParams; 

    surface->getPlaneParams(varParams); // this is the line of code that is different 

    SafeDoubleArray sdParams(varParams); 

    for(int i = 0 ; i < sdParams.getSize() ; ++i) 
    { 
     params.push_back(sdParams[i]); 
    } 

    if(params.size() > 0) return 0; 
    return 1; 
} 

unsigned int CSWX::getPlaneParameters(const CURVE & curve, vector<double> & params) 
{ 
    VARIANT varParams; 

    curve->get_LineParams(varParams); // this is the line of code that is different 

    SafeDoubleArray sdParams(varParams); 

    for(int i = 0 ; i < sdParams.getSize() ; ++i) 
    { 
     params.push_back(sdParams[i]); 
    } 

    if(params.size() > 0) return 0; 
    return 1; 
} 

क्या कोई ऐसी तकनीक है जिसका उपयोग मैं दो विधियों के कोड की सामान्य रेखाओं को एक अलग विधि से स्थानांतरित करने के लिए उपयोग कर सकता हूं, जिसे दो भिन्नताओं से बुलाया जा सकता है - या - संभवतः दो तरीकों को एक विधि में जोड़ना?

निम्न प्रतिबंध हैं:

  1. कक्षाएं सतह और वक्र 3 पार्टी पुस्तकालयों और इसलिए unmodifiable से कर रहे हैं। (यदि यह मदद करता है कि वे दोनों IDispatch से प्राप्त कर रहे)
  2. भी अधिक समान वर्गों (जैसे चेहरा) है कि यह "टेम्पलेट" में खरी उतर सकती हैं (नहीं सी ++ टेम्पलेट, बस कोड की लाइनों के प्रवाह)

मैं निम्नलिखित (? संभवतः) समाधान के रूप में लागू किया जा सकता है, लेकिन वास्तव में आशा करता हूं वहाँ एक बेहतर समाधान है:

  1. मैं 2 तरीकों की एक 3 पैरामीटर जोड़ सकते हैं - जैसे एक enum - जो पहले पैरामीटर की पहचान करता है (उदाहरण के लिए enum :: input_type_surface, enum :: input_type_curve)
  2. मैं एक आईडीस्पैच में पास कर सकता हूं और गतिशील_कास्ट <> और परीक्षण कर सकता हूं कि कौन सी कास्ट NON_NULL है और दाएं कॉल करने के लिए एक और करें विधि (जैसे getPlaneParams() बनाम get_LineParams())

निम्नलिखित एक प्रतिबंध नहीं है, लेकिन अपनी टीम के साथियों प्रतिरोध की वजह से एक आवश्यकता होगा:

  1. नहीं एक नया वर्ग है कि सतह से विरासत को लागू/CURVE इत्यादि। (वे ऊपर बताए गए enum समाधान का उपयोग करके इसे हल करना पसंद करेंगे)
+1

आप 'पैराम्स' वेक्टर को साफ़ नहीं करते हैं। क्या आप इसे कई वस्तुओं से पैरामीटर के साथ भरना चाहते हैं? संभवतः आपके कोड को दोबारा करने के लिए बहुत बेहतर तरीके हैं जो आप geXXXX पैरामीटर विधियों से पहले क्या करते हैं। –

+0

'बूल' पर्याप्त होने पर 'हस्ताक्षरित int' क्यों लौटा रहे हैं? –

+0

'SafeDoubleArray' का प्रकार क्या है? मुझे संदेह है कि यह और अधिक प्रतिक्रिया दे सकता है, लेकिन हमें पहले इसकी आवश्यकता है। मैं 'बूल' के लिए @ मैथ्यूयू की गति को दूसरा स्थान देता हूं। – GManNickG

उत्तर

10

कुछ उपाय दिए मन के लिए आते हैं, लेकिन यहाँ है कि मैं क्या सबसे अच्छा होगा लगता है:

namespace detail 
{ 
    void getParameters(const SURFACE& surface, VARIANT& varParams) 
    { 
     surface->getPlaneParams(varParams); 
    } 

    void getParameters(const CURVE& curve, VARIANT& varParams) 
    { 
     curve->get_LineParams(varParams); 
    } 
} 

template <typename T> 
unsigned int getParameters(const T& curve, vector<double> & params) 
{ 
    VARIANT varParams; 
    detail::getParameters(curve, varParams); 

    SafeDoubleArray sdParams(varParams); 
    for(int i = 0 ; i < sdParams.getSize() ; ++i) 
    { 
     params.push_back(sdParams[i]); 
    } 

    return params.size() != 0; 
} 

आप क्या कुछ अन्य समारोह है कि ओवरलोड हो गया है के लिए मानकों को प्राप्त करने का कार्य सौंपने है। बस आपके पास प्रत्येक अलग-अलग प्रकार के लिए फ़ंक्शंस जोड़ें। (ध्यान दें, मैंने आपके रिटर्न स्टेटमेंट को सरल बना दिया है।)

+0

अच्छा। मुझे यह पसंद है। मैं इसके प्रति झुका रहा हूँ। दुखद मैंने इस बारे में नहीं सोचा था। – ossandcad

+1

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

2

या SURFACE के बजाय फ़ंक्शन के पैरामीटर के रूप में VARIANT varParams क्यों न केवल पास करें?

unsigned int CSWX::getParameters(VARIANT varParams, vector<double> & params) 
{ 
    SafeDoubleArray sdParams(varParams); 

    for(int i = 0 ; i < sdParams.getSize() ; ++i) 
    { 
     params.push_back(sdParams[i]); 
    } 

    if(params.size() > 0) return 0; 
    return 1; 
} 

unsigned int CSWX::getPlaneParameters(const CURVE & curve, vector<double> & params) 
{ 
    VARIANT varParams;  

    curve->get_LineParams(varParams); // this is the line of code that is different 

    return getParameters(varParams, params); 
} 

तुम भी (यदि संभव हो तो) कर रही है उन तरीकों टेम्पलेट्स पर विचार करने और एक vector के बजाय पैरामीटर के रूप में एक output_iterator प्राप्त हो सकता है। इस प्रकार आपका कोड इस्तेमाल किए गए संग्रह के प्रकार पर निर्भर नहीं है।

+0

यह कैसे मदद करेगा? – Dave

+0

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

+0

स्पष्टता के लिए कोड जोड़ा गया। यह समाधान इसे छोटा कर देगा, खासकर यदि अधिक विधियां प्रभावित होती हैं। –

5

Extract Method। आपके द्वारा अलग-अलग रेखाओं के बाद सबकुछ समान है - इसलिए इसे एक विधि के रूप में निकालें जिसे आपके दोनों मूल तरीकों से बुलाया जाता है।

+0

सच - एक अलग विधि के लिए जितना संभव हो उतना सामान्य कोड। यह काम। लेकिन क्या इसका मतलब है, अगर मेरे पास "कोड की अलग-अलग पंक्ति" से पहले अधिक आम कोड है, तो "निकालने" यह मुश्किल होगा? – ossandcad

+0

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

+0

आपको विधि को दो बार निकालना होगा (या अधिक, इस पर निर्भर करता है कि आपके पास कितने स्थान समान कोड हैं)। हां, उस बिंदु पर यह मुश्किल हो सकता है। –

0

सर्फस या सर्व में गुजरने के बजाय, बेस क्लास के संदर्भ में पास करें, और एक विधि फ़ंक्शन पॉइंटर भी।फिर सतह पर कॉल-> getLine_parameters या वक्र-> getPlane पैरामीटर को प्रतिस्थापित किया जाएगा (आकार -> * getParamters) (varParams);

typedef void Baseclass::*ParamGetter(VARIANT varParams); 

unsigned int CSWX::getLineParameters(const Baseclass & geometry, ParamGetter getParams 
     vector<double> & params) 
{ 
    VARIANT varParams; 

    (geometry->*getParams)(varParams); // this is the line of code that is different 

    SafeDoubleArray sdParams(varParams); 

    for(int i = 0 ; i < sdParams.getSize() ; ++i) 
    { 
     params.push_back(sdParams[i]); 
    } 

    if(params.size() > 0) return 0; 
    return 1; 
} 
-2

मैक्रो! आम तौर पर सबसे अच्छा समाधान नहीं है (यह एक मैक्रो है) और शायद इस में वास्तविक सर्वश्रेष्ठ नहीं है, लेकिन यह काम करेगा।

macro_GetDakine_Params(func) 
    VARIANT varParams; \ 
    curve->##func(varParams); // this is the line of code that is different \ 
    SafeDoubleArray sdParams(varParams); \ 
    for(int i = 0 ; i < sdParams.getSize() ; ++i) \ 
    { \ 
     params.push_back(sdParams[i]); \ 
    } \ 
    if(params.size() > 0) return 0; \ 
    return 1; \ 

unsigned int CSWX::getPlaneParameters(const CURVE & curve, vector<double> & params) 
{ 
    macro_GetDakine_Params(getPlaneParams) 
} 
unsigned int CSWX::getLineParameters(const CURVE & curve, vector<double> & params) 
{ 
    macro_GetDakine_Params(getLineParams) 
} 
0

ओ! कृपया, bugged बयान का उपयोग नहीं करते: के बाद से params

return params.size() != 0; 

यह रिटर्न (-1) (सभी बिट्स उठाया) खाली है, नहीं (1)।

लेकिन क्या तुम सच में इस तरह वापसी कथन को मजबूत कर सकते हैं:

return (params.size() != 0) ? 0 : 1; 

ऐसा लगता है वर्गों SURFACE और CURVE लिए सही सार वर्ग FIGURE या SHAPE या कुछ एक और से प्राप्त किया जा करने के लिए। तो आप टेम्पलेट से बच सकते हैं और वर्चुअल ओवरराइडिंग का उपयोग कर सकते हैं:

void getParameters(const FIGURE& surface, VARIANT& varParams) 
संबंधित मुद्दे