पूर्ववत इंजन के लिए डिजाइन पैटर्न


117

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

मैंने पहले से ही एक पूर्ववत इंजन को कोडित कर दिया है जो मॉडल में प्रत्येक संशोधन के बाद एक गहरी प्रतिलिपि को बचाता है। अब मैं सोचने लगा कि क्या मैं अलग तरीके से कोड कर सकता था। गहरी-प्रतियों को सहेजने के बजाय, मैं शायद एक संगत रिवर्स संशोधक के साथ प्रत्येक संशोधक कार्रवाई की एक सूची को बचा सकता हूं। ताकि मैं मौजूदा मॉडल को पूर्ववत करने के लिए रिवर्स मॉडिफ़ायर को पूर्ववत कर सकूं, या संशोधक को फिर से कर सके।

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

इसे लागू करने के बारे में कोई कैसे जानेगा?


अगर मैं टिप्पणी "पूर्ववत् अल्गोरथिम" जोड़ दूं तो यह ऐसा हो जाएगा जिससे मैं "पूर्ववत करें" खोज सकता हूं और यह पा सकता हूं? यही मैंने खोजा और मुझे नकल के रूप में कुछ बंद मिला।
पीटर टर्नर

हाय, मैं भी हम विकसित कर रहे हैं आवेदन में पूर्ववत करें / फिर से करना चाहते हैं। हम क्यूटी 4 फ्रेमवर्क का उपयोग करते हैं और कई जटिल पूर्ववत / फिर से कार्रवाई करने की आवश्यकता है। मैं सोच रहा था, क्या आप कमांड-पैटर्न का उपयोग करने में सफल रहे हैं?
आशिका उमंग उमगिलिया

2
@umanga: यह काम किया लेकिन यह आसान नहीं था। सबसे कठिन हिस्सा संदर्भों पर नज़र रख रहा था। उदाहरण के लिए, जब कोई फ़्रेम ऑब्जेक्ट हटा दिया जाता है, तो उसके बच्चे की वस्तुएं: नोड्स, उस पर अभिनय करने वाले भार और कई अन्य उपयोगकर्ता असाइनमेंट जिन्हें पूर्ववत करने के दौरान रीज़नर किए जाने की आवश्यकता होती है। लेकिन इनमें से कुछ बाल वस्तुओं को अन्य वस्तुओं के साथ साझा किया गया था, और पूर्ववत / फिर से तर्क काफी जटिल हो गए थे। यदि मॉडल इतना बड़ा नहीं था, तो मैं स्मृति चिन्ह को रखूंगा; इसे लागू करना बहुत आसान है।
ओजगुर Ozcitak

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

जवाबों:


88

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


4
यह मूल रूप से कोको, NSUndoManager में पूर्ववत इंजन कैसे काम करता है।
आम्रप

33

मुझे लगता है कि स्मृति और कमान दोनों व्यावहारिक नहीं हैं जब आप आकार और गुंजाइश के एक मॉडल के साथ काम कर रहे हैं जो ओपी का अर्थ है। वे काम करेंगे, लेकिन इसे बनाए रखने और विस्तारित करने के लिए बहुत काम होगा।

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

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

पूर्ववत / फिर से लागू करना सरल है: अपनी कार्रवाई करें और एक नई चौकी स्थापित करें; पिछले चेकपॉइंट पर सभी ऑब्जेक्ट संस्करणों को रोलबैक करें।

यह कोड में कुछ अनुशासन लेता है, लेकिन इसके कई फायदे हैं: आपको मॉडल राज्य के अंतर भंडारण के बाद से गहरी प्रतियों की आवश्यकता नहीं है; आप जिस मेमोरी का उपयोग करना चाहते हैं उसकी मात्रा को कम कर सकते हैं ( CAD मॉडल जैसी चीजों के लिए बहुत महत्वपूर्ण) या तो उपयोग की गई संख्या या मेमोरी द्वारा; मॉडल पर काम करने वाले कार्यों के लिए बहुत स्केलेबल और कम रखरखाव, क्योंकि उन्हें पूर्ववत / फिर से लागू करने के लिए कुछ भी करने की आवश्यकता नहीं है।


1
यदि आप अपने फ़ाइल प्रारूप के रूप में एक डेटाबेस (जैसे sqlite) का उपयोग करते हैं तो यह लगभग स्वचालित हो सकता है
मार्टिन बेकेट

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

क्या आप इस आईडी के बनाम पॉइंटर्स आइडिया के बारे में अधिक बता सकते हैं? निश्चित रूप से एक पॉइंटर / मेमोरी एड्रेस, आईडी के समान ही काम करता है?
पौलमी

@ उत्तर: अनिवार्य रूप से वास्तविक डेटा (आईडी, संस्करण) द्वारा अनुक्रमित किया जाता है। पॉइंटर्स किसी ऑब्जेक्ट के किसी विशेष संस्करण को संदर्भित करते हैं, लेकिन आप किसी वस्तु की वर्तमान स्थिति को संदर्भित करना चाहते हैं, जो कुछ भी हो सकता है, इसलिए आप इसे आईडी (आईडी, संस्करण) द्वारा नहीं, बल्कि आईडी द्वारा संबोधित करना चाहते हैं। आप इसे रिस्ट्रक्चर कर सकते हैं ताकि आप एक पॉइंटर को (वर्जन => डेटा) टेबल पर स्टोर करें और हर बार लेटेस्ट को ही चुनें, लेकिन जब आप डेटा को जारी रख रहे हैं तो लोकलिटी को नुकसान पहुंचाता है, मुडीज़ थोड़ी चिंता करते हैं, और इसे कठिन बना देते हैं सामान्य प्रश्नों के कुछ प्रकार करें, इसलिए यह सामान्य रूप से ऐसा नहीं होगा।
क्रिस मॉर्गन

17

यदि आप GoF की बात कर रहे हैं, तो मेमेंटो पैटर्न विशेष रूप से पूर्ववत पते को दर्शाता है।


7
वास्तव में नहीं, यह उनके प्रारंभिक दृष्टिकोण को संबोधित करता है। वह एक वैकल्पिक दृष्टिकोण के लिए पूछ रहा है। प्रारंभिक प्रत्येक चरण के लिए पूर्ण स्थिति का भंडारण कर रहा है, जबकि उत्तरार्द्ध केवल "भिन्न" का भंडारण कर रहा है।
आंद्रेई रोनेया

15

जैसा कि दूसरों ने कहा है, कमांड पैटर्न पूर्ववत / फिर से लागू करने का एक बहुत शक्तिशाली तरीका है। लेकिन वहाँ महत्वपूर्ण लाभ है जो मैं कमांड पैटर्न का उल्लेख करना चाहूंगा।

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

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

अब, बेशक, बहुत से लोग खुद को सोच रहे हैं "वेल डह, कमांड पैटर्न के बिंदु का हिस्सा नहीं है?" हां, लेकिन मैंने बहुत सारी कमांड सिस्टम देखी हैं जिनमें दो सेट कमांड होते हैं, एक तत्काल ऑपरेशन के लिए और दूसरा पूर्ववत / रीडो के लिए सेट होता है। मैं यह नहीं कह रहा हूं कि ऐसे कमांड नहीं होंगे जो तत्काल संचालन और पूर्ववत / फिर से करने के लिए विशिष्ट हों, लेकिन दोहराव को कम करने से कोड को बनाए रखा जा सकेगा।


1
मैं कभी नहीं सोचा गया है pasteके रूप में cut^ -1।
होयट

8

आप अपने पूर्ववत के लिए Paint.NET कोड को संदर्भित करना चाह सकते हैं - उन्हें वास्तव में अच्छा पूर्ववत सिस्टम मिल गया है। यह शायद आप की आवश्यकता की तुलना में थोड़ा सरल है, लेकिन यह आपको कुछ विचार और दिशानिर्देश दे सकता है।

-Adam


4
दरअसल, Paint.NET कोड अब उपलब्ध नहीं है, लेकिन आप forked code.google.com/p/paint-mono
Igor Brejc

7

यह एक ऐसा मामला हो सकता है जहां CSLA लागू है। इसे विंडोज फॉर्म एप्लिकेशन में ऑब्जेक्ट्स को जटिल पूर्ववत सहायता प्रदान करने के लिए डिज़ाइन किया गया था।


6

मैंने जटिल पूर्ववत सिस्टम को बहुत ही सरलता से मेमेंटो पैटर्न का उपयोग करके कार्यान्वित किया है - बहुत आसान है, और स्वाभाविक रूप से एक रेडो फ्रेमवर्क भी प्रदान करने का लाभ है। एक और अधिक सूक्ष्म लाभ यह है कि कुल क्रियाओं को एक ही पूर्ववत में भी समाहित किया जा सकता है।

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

आपके दस्तावेज़ की स्थिति को बदलने का तरीका कैसे लागू किया जाता है, यह आपके कार्यान्वयन पर पूरी तरह निर्भर करता है। यदि आप बस एक API कॉल कर सकते हैं (जैसे ChangeColour (r, g, b)), तो संबंधित राज्य को प्राप्त करने और सहेजने के लिए इसे एक क्वेरी से पहले लें। लेकिन पैटर्न भी गहरी प्रतियां, मेमोरी स्नैपशॉट, अस्थायी फ़ाइल निर्माण आदि बनाने का समर्थन करेगा - यह सब आपके ऊपर है क्योंकि यह बस एक आभासी विधि कार्यान्वयन है।

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

कई पूर्ववत् प्रणालियाँ केवल इन-मेमोरी हैं, लेकिन आप चाहें तो पूर्ववत किए गए स्टैक को जारी रख सकते हैं, मुझे लगता है।


5

बस मेरी चुस्त विकास पुस्तक में कमांड पैटर्न के बारे में पढ़ रहे हैं - शायद यह संभावित है?

आपके पास कमांड इंटरफ़ेस लागू करने का प्रत्येक आदेश हो सकता है (जिसमें एक निष्पादन () विधि है)। यदि आप पूर्ववत करना चाहते हैं, तो आप एक पूर्ववत् विधि जोड़ सकते हैं।

अधिक जानकारी यहाँ


4

मैं Mendelt Siebenga के साथ इस तथ्य पर हूं कि आपको कमांड पैटर्न का उपयोग करना चाहिए। आपके द्वारा उपयोग किया जाने वाला पैटर्न मेमेंटो पैटर्न था, जो समय के साथ बहुत ही बेकार हो जाता है।

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

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


3

कोडप्लेक्स प्रोजेक्ट :

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


2

अधिकांश उदाहरण जो मैंने पढ़े हैं, वे कमांड या स्मृति चिन्ह पैटर्न का उपयोग करके करते हैं। लेकिन आप इसे डिजाइन पैटर्न के बिना भी कर सकते हैं एक सरल संरचना-संरचना के साथ


आप क्या करना चाहते हैं?

मेरे मामले में मैंने उन ऑपरेशनों की वर्तमान स्थिति बताई जिन्हें मैं पूर्ववत करना चाहता था / फिर से कार्यक्षमता के लिए। दो देवताओं (पूर्ववत करें / फिर से करें) के द्वारा मैं पूर्ववत कतार (पॉप प्रथम आइटम) पर पूर्ववत करें और इसे फिर से डालें। यदि छंदों में मदों की संख्या पसंदीदा आकार से अधिक है तो मैं पूंछ के एक आइटम को पॉप करता हूं।
पैट्रिक स्वेन्सन

2
क्या आप वास्तव में वर्णन है एक डिजाइन पैटर्न :)। इस दृष्टिकोण के साथ समस्या यह है कि जब आपका राज्य बहुत अधिक स्मृति लेता है - कई दर्जनों राज्य संस्करण रखते हैं तो यह अव्यावहारिक या असंभव भी हो जाता है।
इगोर ब्रेजक

या आप सामान्य और पूर्ववत संचालन का प्रतिनिधित्व करने वाली जोड़ी को बंद कर सकते हैं।
Xwtek

2

पूर्ववत् संभाल करने का एक चतुर तरीका, जो आपके सॉफ़्टवेयर को बहु उपयोगकर्ता सहयोग के लिए भी उपयुक्त बनाता है, डेटा संरचना के परिचालन परिवर्तन को लागू कर रहा है

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



1

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

ऑब्जेक्ट्स (C ++) की ओर इशारा करते हुए कई MANY बग्स आए हैं जिन्हें कभी भी ठीक नहीं किया गया था क्योंकि आप कुछ अजीब पूर्ववत अनुक्रम करते हैं (उन स्थानों को "पहचानकर्ता" को पूर्ववत करने के लिए अद्यतन नहीं किया गया है)। इस क्षेत्र में कीड़े अक्सर ... उम्म ... दिलचस्प।

कुछ ऑपरेशन गति / संसाधन उपयोग के लिए विशेष मामले हो सकते हैं - जैसे चीजों को आकार देना, चीजों को इधर-उधर करना।

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


जैसा कि आपके मॉडल का आकार बढ़ता है, यह तेजी से अस्थिर लगता है।
वॉरेन पी

किस तरह से? यह दृष्टिकोण बिना बदलाव के काम करता रहता है क्योंकि प्रत्येक वस्तु में नई "चीजें" जोड़ी जाती हैं। प्रदर्शन एक मुद्दा हो सकता है क्योंकि वस्तुओं का क्रमबद्ध रूप आकार में बढ़ता है - लेकिन यह एक बड़ी समस्या नहीं है। सिस्टम 20+ वर्षों से निरंतर विकास के अधीन है और उपयोगकर्ताओं के अधिक उपयोग से है।
एर्डवार्क

1

मुझे ऐसा तब करना था जब एक खूंटी-कूद पहेली खेल के लिए एक सॉल्वर लिख रहा था। मैंने प्रत्येक एक कमांड ऑब्जेक्ट को स्थानांतरित किया, जिसमें पर्याप्त जानकारी थी कि यह या तो किया जा सकता है या पूर्ववत किया जा सकता है। मेरे मामले में यह शुरुआती स्थिति और प्रत्येक चाल की दिशा को संग्रहीत करने जैसा सरल था। मैं तो इन सभी वस्तुओं को एक स्टैक में संग्रहीत करता हूं ताकि प्रोग्राम आसानी से कई चालों को पूर्ववत कर सके क्योंकि इसे पीछे ले जाने की आवश्यकता थी।


1

आप PostSharp में Undo / Redo पैटर्न के तैयार कार्यान्वयन की कोशिश कर सकते हैं। https://www.postsharp.net/model/undo-redo

यह आपको पैटर्न को लागू किए बिना अपने एप्लिकेशन में पूर्ववत / पुन: कार्यक्षमता जोड़ने की सुविधा देता है। यह आपके मॉडल में परिवर्तनों को ट्रैक करने के लिए रिकॉर्ड करने योग्य पैटर्न का उपयोग करता है और यह INotifyPropertyChanged पैटर्न के साथ काम करता है जो कि PostSharp में भी लागू किया जाता है।

आपको UI नियंत्रण प्रदान किया जाता है और आप यह तय कर सकते हैं कि प्रत्येक ऑपरेशन का नाम और बारीकता क्या होगी।


0

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


0

डिजाइन पैटर्न (गोफ, 1994) के पहले खंड में डिजाइन पैटर्न के रूप में पूर्ववत / फिर से लागू करने के लिए उपयोग का मामला है।


0

आप अपने प्रारंभिक विचार को परफॉर्म कर सकते हैं।

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


0

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

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

एक उदाहरण के लिए यहां देखें: https://github.com/thilo20/Undo/


-1

मुझे नहीं पता कि यह आपके किसी काम का है या नहीं, लेकिन जब मुझे अपने एक प्रोजेक्ट पर कुछ ऐसा ही करना था, तो मैंने http://www.undomadeeasy.com से UndoEngine को डाउनलोड करना समाप्त कर दिया - एक अद्भुत इंजन और मैं वास्तव में बहुत ज्यादा परवाह नहीं करता था कि बोनट के नीचे क्या था - यह सिर्फ काम करता है।


कृपया अपनी टिप्पणियों को उत्तर के रूप में पोस्ट करें यदि आप समाधान प्रदान करने के लिए आश्वस्त हैं! अन्यथा प्रश्न के तहत टिप्पणी के रूप में पोस्ट करना पसंद करें! (यदि यह अब ऐसा करने की अनुमति नहीं देता है! तो कृपया अच्छी प्रतिष्ठा पाने तक प्रतीक्षा करें)
शिशुप्रधान अरविंद '

-1

मेरी राय में, UNDO / REDO को 2 तरीकों से मोटे तौर पर लागू किया जा सकता है। 1. कमांड लेवल (कमांड लेवल अनडू / रीडो कहा जाता है) 2. डॉक्यूमेंट लेवल (जिसे ग्लोबल अनडू / रीडो कहा जाता है)

कमांड स्तर: जैसा कि कई उत्तर बताते हैं, यह मेमेंटो पैटर्न का उपयोग करके कुशलता से प्राप्त किया गया है। यदि कमांड एक्शन को जर्नलिज्म करने में भी मदद करता है, तो एक रीडो आसानी से सपोर्ट करता है।

सीमा: एक बार कमांड के दायरे से बाहर होने के बाद, पूर्ववत करें / फिर से करना असंभव है, जो दस्तावेज़ स्तर (वैश्विक) पूर्ववत करें / फिर से ले जाता है

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

  1. सभी मेमोरी पूर्ववत करें / फिर से करें
  2. ऑब्जेक्ट का स्तर पूर्ववत करें

"सभी मेमोरी पूर्ववत करें / फिर से करें" में, संपूर्ण मेमोरी को कनेक्टेड डेटा (जैसे कि एक पेड़, या एक सूची या एक ग्राफ) के रूप में माना जाता है और मेमोरी को ओएस के बजाय एप्लिकेशन द्वारा प्रबंधित किया जाता है। यदि C ++ में प्रभावी ढंग से संचालन को लागू करने के लिए अधिक विशिष्ट संरचनाएं सम्‍मिलित हैं तो नए और हटाए गए ऑपरेटर। यदि कोई नोड संशोधित किया गया है, तो बी। डेटा आदि को रखना और साफ़ करना, यह जिस तरह से कार्य करता है वह मूल रूप से संपूर्ण मेमोरी को कॉपी करना है (यह मानते हुए कि मेमोरी आवंटन पहले से ही अनुकूलित एल्गोरिदम का उपयोग करके आवेदन द्वारा अनुकूलित और प्रबंधित किया गया है) और इसे स्टैक में संग्रहीत करें। यदि स्मृति की प्रतिलिपि का अनुरोध किया जाता है, तो उथले या गहरी प्रतिलिपि की आवश्यकता के आधार पर पेड़ की संरचना की प्रतिलिपि बनाई जाती है। एक गहरी प्रतिलिपि केवल उस चर के लिए बनाई गई है जिसे संशोधित किया गया है। चूंकि प्रत्येक चर को कस्टम आवंटन का उपयोग करके आवंटित किया गया है, अगर जरूरत हो तो इसे हटाने के लिए एप्लिकेशन का अंतिम कहना है। चीजें बहुत दिलचस्प हो जाती हैं अगर हमें पूर्ववत / फिर से विभाजन करना पड़ता है जब ऐसा होता है कि हमें प्रोग्रामेटिक रूप से पूर्ववत करें / फिर से करें संचालन का एक सेट। इस मामले में, केवल उन नए चर, या हटाए गए चर या संशोधित चर को एक ध्वज दिया जाता है ताकि पूर्ववत करें / फिर से करें केवल उन स्मृतियों को पूर्ववत् / घटाता है यदि हम किसी वस्तु के अंदर आंशिक पूर्ववत / फिर से करना चाहते हैं तो चीजें और भी दिलचस्प हो जाती हैं। जब ऐसा होता है, तो "विज़िटर पैटर्न" के एक नए विचार का उपयोग किया जाता है। इसे "ऑब्जेक्ट स्तर पूर्ववत करें / फिर से करें" कहा जाता है या हटाए गए चर या संशोधित चर को एक ध्वज दिया जाता है ताकि पूर्ववत करें / फिर से करें केवल उन्ही मेमोरी को अनडू / रीडू करता है यदि हम किसी वस्तु के अंदर आंशिक पूर्ववत / फिर से करना चाहते हैं तो चीजें और भी दिलचस्प हो जाती हैं। जब ऐसा होता है, तो "विज़िटर पैटर्न" के एक नए विचार का उपयोग किया जाता है। इसे "ऑब्जेक्ट स्तर पूर्ववत करें / फिर से करें" कहा जाता है या हटाए गए चर या संशोधित चर को एक ध्वज दिया जाता है ताकि पूर्ववत करें / फिर से करें केवल उन्ही मेमोरी को अनडू / रीडू करता है यदि हम किसी वस्तु के अंदर आंशिक पूर्ववत / फिर से करना चाहते हैं तो चीजें और भी दिलचस्प हो जाती हैं। जब ऐसा होता है, तो "विज़िटर पैटर्न" के एक नए विचार का उपयोग किया जाता है। इसे "ऑब्जेक्ट स्तर पूर्ववत करें / फिर से करें" कहा जाता है

  1. ऑब्जेक्ट स्तर पूर्ववत करें / फिर से करें: जब पूर्ववत / फिर से करने की अधिसूचना को कहा जाता है, तो प्रत्येक वस्तु एक स्ट्रीमिंग ऑपरेशन को लागू करती है, जिसमें स्ट्रीमर ऑब्जेक्ट से पुराने डेटा / नए डेटा को प्राप्त करता है जिसे प्रोग्राम किया जाता है। जो डेटा डिस्टर्ब नहीं होता है, उसे छोड़ दिया जाता है। प्रत्येक ऑब्जेक्ट को तर्क के रूप में एक स्ट्रीमर मिलता है और UNDo / Redo कॉल के अंदर, यह ऑब्जेक्ट के डेटा को स्ट्रीम / अनस्ट्रीम करता है।

1 और 2 दोनों की विधियाँ हो सकती हैं जैसे 1. बिफोरंडो () 2. आफ्टरएंडो () 3. बिफोरडो () 4. आफ्टरएडो ()। इन तरीकों को मूल पूर्ववत / फिर से आदेश (संदर्भ आदेश नहीं) में प्रकाशित किया जाना है ताकि सभी ऑब्जेक्ट इन विधियों को भी लागू कर सकें ताकि विशिष्ट कार्रवाई हो सके।

एक अच्छी रणनीति 1 और 2. का संकर बनाना है। सुंदरता यह है कि ये विधियाँ (1 और 2) स्वयं कमांड पैटर्न का उपयोग करती हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.