2012-11-15 15 views
10

काफी समय से मैं एक आवेदन पर काम कर रहा हूं। चूंकि प्रोग्रामिंग सिर्फ एक शौक है, यह प्रोजेक्ट पहले से ही बहुत लंबा रास्ता ले रहा है, लेकिन यह बिंदु के अलावा है। अब मैं एक बिंदु पर हूं जहां हर "समस्या" हल करने में बहुत मुश्किल हो जाती है। और मैं कोड को दोबारा प्रतिक्रिया देने की सोच रहा हूं, हालांकि इसके परिणामस्वरूप "पूर्ण" पुनर्लेखन होगा।प्रोग्रामिंग प्रतिमान; यह सोचकर कि पुनः लिखना/रीफैक्टरिंग आवश्यक है

मुझे समस्या की व्याख्या करने दें, और मैंने इसे वर्तमान में कैसे हल किया। असल में मेरे पास डेटा है, और मैंने इस डेटा पर चीजों को होने दिया है (अच्छी तरह से मैंने प्रत्येक कार्यक्रम के बारे में बताया है?)। क्या होता है:

डाटा -> पूछता है प्रदर्शित करने के लिए दर्शक -> दर्शक को प्रदर्शित करता है वास्तविक डेटा के आधार पर डेटा दर्शक रिटर्न उपयोगकर्ता इनपुट -> डेटा -> पूछते हैं, "प्रबंधक" यह निष्पादित करने के लिए -> नए डेटा

enter image description here

अब इस बहुत अच्छी तरह से काम करता था, और मैं "क्यूटी द्वारा हे मैं उदाहरण परिवर्तन कमांड प्रॉम्प्ट के लिए हो सकता है, या खिड़कियों - या यहाँ तक कि ले कि बाहरी (सी #) और केवल इस कार्यक्रम कॉल" मूल रूप से सोच रहा था ।

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

नई "डेटा" के लिए अद्यतन करते समय समस्याएं शुरू होती हैं - मुझे सभी संपत्तियों - दर्शक, सेवर इत्यादि के माध्यम से जाना होगा। चेक-मैकेनिज्म को अद्यतन करने से मुझे बहुत सारी त्रुटियां मिलीं .. चीजें जैसे "हे, यह अब गलत विजेट क्यों प्रदर्शित कर रहा है?"

अब मैं इसे पूरी तरह से स्वैप कर सकता हूं। और पेड़ डेटास्ट्रक्चर के बजाय एक सामान्य दर्शक को बुला रहा हूं। मैं ओओ "आंतरिक" वृक्ष क्षमताओं का उपयोग करूंगा। नोड्स बच्चे होंगे (& whe n एक नया दर्शक या सहेजने की आवश्यकता है एक नया बच्चा बनता है)।

यह कठिन जांच तंत्र को हटा देगा, जहां मैं पेड़ में स्थान की जांच करता हूं। हालांकि यह कीड़े का एक और अन्य खुल सकता है। और मुझे इस पर कुछ टिप्पणियां चाहिए? क्या मुझे दर्शक को पूरी तरह से अलग रखना चाहिए - डेटा की जांच में कठिनाई हो रही है? या नया दृष्टिकोण बेहतर है, फिर भी यह एक एकल नोड में डेटा & निष्पादन को जोड़ता है। (तो मैं कहने के लिए CLI/सी # यह लगभग असंभव हो जाता है क्यूटी से परिवर्तन करना चाहते हैं, तो)

enter image description here

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

संपादित करें, बस कुछ "कोड" दिखाने के लिए और मेरा प्रोग्राम कैसे काम करता है। यकीन नहीं है कि यह कोई अच्छा है जैसा कि मैंने पहले ही कहा था कि यह पद्धतियों के क्लस्टरफक बन गया है।

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

कहा जा रहा है कि वहां बहुत सारे अंक हैं जहां नोड बिल्कुल वही है .. जैसे पृष्ठभूमि में <width>200</width> हो सकता है और एक कमरे में भी हो सकता है। फिर भी उपयोगकर्ता के लिए यह काफी महत्वपूर्ण है कि वह किस चौड़ाई के बारे में बात कर रहा है।

फिर भी

, तो "सामान्य दर्शक" (AskGUIFn) निम्नलिखित typedefs इस संभाल करने के लिए है:

typedef int (AskGUIFn::*MemberFn)(const GMProject::pTree& tOut, const GMProject::pTree& tIn, int) const; 
    typedef std::vector<std::pair<boost::regex, MemberFn> > DisplaySubMap_Ty; 
    typedef std::map<RESOURCE_TYPES, std::pair<DisplaySubMap_Ty, MemberFn> > DisplayMap_Ty; 

कहाँ "GMProject :: pTree" एक पेड़ नोड है, RESOURCE_TYPES में ट्रैक रखने के लिए एक स्थिर है इस समय मैं किस प्रकार का संसाधन हूं (स्प्राइट, ऑब्जेक्ट इत्यादि)। "सदस्यएफएन" यहां कुछ ऐसा होगा जो विजेट लोड करता है। (हालांकि AskGUIFn पाठ्यक्रम का एकमात्र सामान्य दर्शक नहीं है, लेकिन यह केवल तब खोला जाता है जब अन्य "स्वचालित" -प्रोराइट, छोड़ें, नाम बदलें- हैंडलर विफल हो गए हैं)। जब पेड़ आंकड़ा संरचना सामान्य दर्शक यह दर्शक को निष्पादित करता है प्रदर्शित करने के लिए चाहता है बताता है

AskGUIFn::DisplayMap_Ty AskGUIFn::DisplayFunctionMap_INIT() { 
    DisplayMap_Ty t; 
     DisplaySubMap_Ty tmp; 

     tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^instances "), &AskGUIFn::ExecuteFn<MW::RoomInstanceDialog>)); 
     tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^code $"), &AskGUIFn::ExecuteFn<MW::RoomStringDialog>)); 
     tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^(isometric|persistent|showcolour|enableViews|clearViewBackground) $"), &AskGUIFn::ExecuteFn<MW::ResourceBoolDialog>)); 
     //etc etc etc 
    t[RT_ROOM] = std::pair<DisplaySubMap_Ty, MemberFn> (tmp, &AskGUIFn::ExecuteFn<MW::RoomStdDialog>); 

     tmp.clear(); 
     //repeat above 
    t[RT_SPRITE] = std::pair<DisplaySubMap_Ty, MemberFn>(tmp, &AskGUIFn::ExecuteFn<MW::RoomStdDialog>); 
    //for each resource type. 

तब:

अब दिखाने के लिए कि कैसे इन नक्शे प्रारंभ कर रहे हैं (नाम स्थान "मेगावाट" में सब कुछ एक क्यूटी विजेट है) निम्नलिखित समारोह:

AskGUIFn::MemberFn AskGUIFn::FindFirstMatch() const { 
    auto map_loc(DisplayFunctionMap.find(res_type)); 
    if (map_loc != DisplayFunctionMap.end()) { 
     std::string stack(CallStackSerialize()); 
     for (auto iter(map_loc->second.first.begin()); iter != map_loc->second.first.end(); ++iter) { 
      if (boost::regex_search(stack, iter->first)) { 
       return iter->second; 
      } 
     } 
     return map_loc->second.second; 
    } 

    return BackupScreen; 
} 

और यह वह जगह है जहाँ समस्याओं खुलकर होने के लिए शुरू कर दिया।CallStackSerialize() फ़ंक्शन कॉल-स्टैक पर निर्भर करता है .. हालांकि कॉल_स्टैक को "हैंडलर" के अंदर संग्रहीत किया जाता है। मैंने इसे वहां संग्रहित किया क्योंकि सबकुछ एक हैंडलर से शुरू होता है। मुझे सच में यकीन नहीं है कि मुझे यह "call_stack" कहां स्टोर करना चाहिए। एक और ऑब्जेक्ट पेश करें जो ट्रैक करता है कि क्या हो रहा है? मैंने उस मार्ग पर जाने की कोशिश की जहां मैं माता-पिता को नोड के साथ ही स्टोर करता हूं। (कॉल-स्टैक की आवश्यकता को रोकना)। हालांकि, साथ ही साथ मैं कामना नहीं करता था: प्रत्येक नोड में केवल एक वेक्टर होता है जिसमें उसके बच्चे नोड होते हैं। इसलिए पॉइंटर्स का उपयोग माता-पिता नोट को इंगित करने के लिए प्रश्न से बाहर है ... (पीएस: शायद मुझे इसे किसी अन्य प्रश्न में सुधारना चाहिए ..)

+6

+1। सवाल पढ़ने के बिना, यह बस अच्छा लग रहा है। – iammilind

+2

क्या आप "[इनर प्लेटफार्म इफेक्ट] (http://en.wikipedia.org/wiki/Inner_platform_effect) से परिचित हैं?" मैं आपकी समस्या को किसी भी निष्कर्ष निकालने के लिए पर्याप्त रूप से समझ नहीं पा रहा हूं (और मुझे निश्चित रूप से आपके आवेदन के बारे में कुछ नहीं पता!) लेकिन यदि आप इस शब्द से परिचित नहीं हैं तो यह थोड़ा सा शोध है। एक सुपर सामान्य उद्देश्य ढांचे के लिए एक बहुत ही जटिल प्रणाली को संशोधित करने के लिए संघर्ष करना इस विशेष एंटीपार्टर्न के लक्षण की तरह लगता है ... – Rook

+0

यह नहीं है कि आपके डेटा नोड्स को एक प्रकार की प्रोफ़ाइल की आवश्यकता होती है जब वे बनाए जाते हैं, प्रोफाइल यह बताता है कि कैसे उपस्थित होने, उन्हें कार्य करने और बचाने के लिए? – armel

उत्तर

2

एक समर्पित कक्षा में दर्शकों के बाहर इस जटिल स्थान जांच तंत्र को दोबारा प्रतिक्रिया/पुन: लिखना समझ में आता है, ताकि आप अपने शेष कार्यक्रम को प्रभावित किए बिना अपना समाधान सुधार सकें। आइए इसे NodeToWidgetMap पर कॉल करें।

वास्तुकला
एक Model-View-Controller वास्तुकला जो IMO एक अच्छी बात है की दिशा में अपनी शीर्षक लगता है। आपकी वृक्ष संरचना और इसके नोड मॉडल हैं, जहां दर्शक और "विजेट" दृश्य हैं, और नोड के आधार पर तर्क चुनने वाले विजेट नियंत्रक का हिस्सा होंगे।

मुख्य प्रश्न तब होता है जब आप दिए गए नोड एन के लिए विजेट w एन चुनते हैं और इस विकल्प को कैसे स्टोर करते हैं।

NodeToWidgetMap: जब
चयन करने के लिए आप यह मान सकते हैं कि डब्ल्यू एन अपने जीवनकाल के दौरान परिवर्तन नहीं करता है, भले ही नोड्स ले जाया जाता है, आप इसे सही जब नोड बनाने चुन सकते हैं। अन्यथा आपको स्थान (या एक्सएमएल के माध्यम से पथ) को जानना होगा और इसके परिणामस्वरूप, अनुरोध करते समय नोड के माता-पिता को ढूंढें।

ढूँढना जनक नोड्स
मेरे समाधान, नोड उदाहरणों खुद को के बजाय को संकेत स्टोर करने के लिए शायद boost::shared_ptr का उपयोग कर किया जाएगा। इसमें कमी है, उदाहरण के लिए नोड्स की प्रतिलिपि बनाने से आप अपने स्वयं के प्रति-निर्माणकर्ताओं को लागू करने के लिए मजबूर कर सकते हैं जो आपके उप-पेड़ की गहरी प्रतिलिपि बनाने के लिए पुनरावृत्ति का उपयोग करते हैं। (हालांकि मूविंग बच्चे नोड्स को प्रभावित नहीं करेगा।)

विकल्प मौजूद हैं, जैसे माता-पिता नोड को छूने के दौरान बच्चे नोड्स को अपरिवर्तित रखना, दादा वेक्टर के संबंध में। या आप Node::findParentOf(node) फ़ंक्शन को परिभाषित कर सकते हैं यह जानकर कि कुछ नोड्स केवल (या अक्सर) कुछ नोड्स के बच्चे के रूप में पाए जा सकते हैं। यह क्रूर है लेकिन छोटे पेड़ के लिए काफी अच्छी तरह से काम करेगा, बस बहुत अच्छी तरह से स्केल नहीं करता है।

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

आपका वर्तमान दृष्टिकोण एक्सएमएल पथ (ढेर) से मेल खाने के लिए नियमित अभिव्यक्तियों का उपयोग करना है।

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

NodeToWidgetMap: जहां चुनाव
प्रत्येक नोड के लिए एक अद्वितीय, सांख्यिक आईडी संबद्ध कर रहा है स्टोर करने के लिए, नोड आईडी से एक मानचित्र का उपयोग NodeToWidgetMap अंदर विजेट विजेट पसंद रिकॉर्ड है।

बनाम पुनर्रचना
नए सिरे से लिखना आप को फिर से लिखने अगर आप आदेश में इस तरह के रूप में अच्छा क्यूटी एक मौजूदा ढांचे को tieing लाभ उठाने मिल सकता है बजाय पहियों को फिर से लिखने के अपने कार्यक्रम पर ध्यान दें।प्रत्येक मंच के pecularities के चारों ओर अमूर्त के मुकाबले ढांचे पर एक अच्छी तरह से लिखित कार्यक्रम पोर्ट करना आसान हो सकता है। क्यूटी एमवीसी-आर्किटेक्चर के अनुभव और अच्छी समझ हासिल करने के लिए एक अच्छा ढांचा है।

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

+1

मेह मैं निश्चित रूप से फिर से लिखने जा रहा हूं मुझे लगता है .. यह परियोजना वास्तव में बहुत सारे बदलाव दिखाती है। इससे पहले मैं सिर्फ "सी ++/एसटीएल के साथ कुशल" था, हालांकि मैंने कभी भी कुछ भी बड़ा नहीं किया। अब मैंने क्यूटी सीख लिया, और मुझे कई अन्य चीजें चाहिए (सी ++ 11)। मैं कोड शैली में वास्तव में उस बिंदु पर अंतर देख सकता हूं जो मुझे शर्मिंदा है। – paul23

+0

मेह, कई संपादनों के लिए खेद है, ऐसा लगता है कि आप "कठिनाई के संरक्षण के कानून" में भाग लेते हैं –

+0

हम्म अच्छी तरह से मैं वास्तव में "नोडकिंड" दृष्टिकोण के साथ जा सकता हूं; नोड्स अपना प्रकार रखेंगे (और केवल अन्य पेड़ों में जोड़े गए हैं)। हालांकि यह – paul23

1

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

0

Pedro NF ने कहा, मार्टिन फाउलर "Refactoring" इससे परिचित होने के लिए अच्छी जगह है।

0

मैं रॉबर्ट मार्टिन "एग्इल सिद्धांतों, पैटर्न और प्रथाओं में सी # की एक प्रति खरीदने की सलाह देता हूं" वह कुछ बहुत ही व्यावहारिक केस अध्ययनों पर जाता है जो दिखाता है कि इस तरह रखरखाव की समस्याओं को कैसे दूर किया जाए।

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