जी, ब्रायन, काश मैं आपके प्रश्न को जल्द देख लेता। चूंकि यह मेरा "आविष्कार" (बेहतर या बदतर के लिए) बहुत है, इसलिए मैं मदद करने में सक्षम हो सकता हूं।
सम्मिलित: सबसे कम संभव व्याख्या जो मैं कर सकता हूं वह यह है कि यदि सामान्य निष्पादन हवा में गेंद फेंकने और उसे पकड़ने जैसा है, तो अंतर निष्पादन बाजीगरी की तरह है।
@ विंडफाइंडर की व्याख्या खान से अलग है, और यह ठीक है। इस तकनीक को किसी के सिर के चारों ओर लपेटना आसान नहीं है, और मुझे स्पष्टीकरण के लिए 20 साल (ऑफ और ऑन) लगे हैं ताकि स्पष्टीकरण मिल सके। मुझे इसे एक और शॉट यहाँ दें:
हम सभी एक कंप्यूटर के सरल विचार को एक प्रोग्राम के माध्यम से समझते हैं, जो इनपुट डेटा के आधार पर सशर्त शाखाएं लेते हैं, और चीजें करते हैं। (मान लें कि हम केवल सरल संरचित गोटो-कम, रिटर्न-कम कोड के साथ काम कर रहे हैं।) उस कोड में स्टेटमेंट्स, बेसिक स्ट्रक्चर्ड कंडीशन्स, सिंपल लूप्स और सबरूटीन कॉल्स के सीक्वेंस होते हैं। (अभी के लिए मान लौटाने वाले कार्यों के बारे में भूल जाएं।)
अब दो कंप्यूटरों को एक ही कोड को एक-दूसरे के साथ लॉक-स्टेप में निष्पादित करने की कल्पना करें, और नोटों की तुलना करने में सक्षम हों। कंप्यूटर 1 इनपुट डेटा ए के साथ चलता है, और कंप्यूटर 2 इनपुट डेटा बी के साथ चलता है। वे चरण-दर-चरण चलते हैं। यदि वे IF (परीक्षण) जैसे एक सशर्त विवरण में आते हैं .... ENDIF, और यदि उनके पास इस बात पर मतभेद है कि क्या परीक्षण सत्य है, तो वह जो परीक्षण कहता है कि यदि ENDIFIF गलत है और इसके लिए प्रतीक्षा करता है अपनी बहन को पकड़ने के लिए। (यही कारण है कि कोड संरचित है, इसलिए हमें पता है कि बहन अंततः ENDIF को मिल जाएगी।)
चूंकि दोनों कंप्यूटर एक-दूसरे से बात कर सकते हैं, वे नोटों की तुलना कर सकते हैं और इनपुट डेटा के दो सेट और निष्पादन हिस्टरी के बारे में विस्तृत विवरण दे सकते हैं।
बेशक, अंतर निष्पादन (डीई) में यह एक कंप्यूटर के साथ किया जाता है, दो का अनुकरण करता है।
अब, मान लीजिए कि आपके पास इनपुट डेटा का केवल एक सेट है, लेकिन आप यह देखना चाहते हैं कि यह समय-समय पर 1 से कैसे बदल गया है। मान लीजिए कि आप जिस प्रोग्राम को निष्पादित कर रहे हैं, वह एक धारावाहिक / डेज़राइज़र है। जैसा कि आप निष्पादित करते हैं, आप दोनों वर्तमान डेटा को लिखते हैं और पिछले डेटा (जो पिछली बार आपने ऐसा किया था लिखा था) में deserialize (पढ़ें)। अब आप आसानी से देख सकते हैं कि पिछली बार डेटा क्या था और इस समय क्या है, इसके बीच क्या अंतर हैं।
जिस फ़ाइल को आप लिख रहे हैं, और जिस पुरानी फ़ाइल से आप पढ़ रहे हैं, वह एक साथ ली गई एक कतार या FIFO (पहली-पहली-पहली-आउट) है, लेकिन यह बहुत गहरी अवधारणा नहीं है।
- ये किस काम के लिए अच्छा है?
यह मेरे लिए तब हुआ जब मैं एक ग्राफिक्स प्रोजेक्ट पर काम कर रहा था, जहां उपयोगकर्ता "प्रतीकों" नामक छोटे डिस्प्ले-प्रोसेसर रूटीन का निर्माण कर सकता था, जिन्हें पाइप, टैंक, वाल्व, सामान जैसे आरेख जैसी चीजों को चित्रित करने के लिए बड़े रूटीन में इकट्ठा किया जा सकता था। हम चाहते थे कि आरेख "गतिशील" इस अर्थ में हो कि वे पूरे आरेख को फिर से खोले बिना अपने आप को अपडेट कर सकें। (हार्डवेयर आज के मानकों से धीमा था।) मैंने महसूस किया कि (उदाहरण के लिए) एक बार-चार्ट की एक पट्टी खींचने के लिए एक दिनचर्या अपनी पुरानी ऊंचाई को याद कर सकती है और बस खुद को अपडेट कर सकती है।
यह OOP की तरह लगता है, है ना? हालांकि, "बनाने" के बजाय एक "वस्तु", मैं आरेख प्रक्रिया के निष्पादन अनुक्रम की पूर्वानुमेयता का लाभ उठा सकता था। मैं एक अनुक्रमिक बाइट-स्ट्रीम में बार की ऊंचाई लिख सकता था। फिर छवि को अपडेट करने के लिए, मैं सिर्फ एक मोड में प्रक्रिया को चला सकता हूं जहां यह क्रमिक रूप से अपने पुराने मापदंडों को पढ़ता है जबकि यह नए मापदंडों को लिखता है ताकि अगले अपडेट पास के लिए तैयार रहें।
यह मूर्खतापूर्ण स्पष्ट लगता है और जैसे ही प्रक्रिया में एक सशर्त शामिल होता है, ऐसा लगता है, क्योंकि तब नई धारा और पुरानी धारा सिंक से बाहर हो जाएगी। लेकिन तब यह मुझ पर हावी हो गया कि अगर वे सशर्त परीक्षण के बूलियन मूल्य को क्रमबद्ध करते हैं, तो वे सिंक में वापस आ सकते हैं । खुद को समझाने में थोड़ा समय लगा और फिर यह साबित करने के लिए कि यह हमेशा काम करेगा , बशर्ते एक सरल नियम ("इरेज़ मोड रूल") का पालन किया जाए।
शुद्ध परिणाम यह है कि उपयोगकर्ता इन "गतिशील प्रतीकों" को डिजाइन कर सकता है और उन्हें बड़े आरेखों में इकट्ठा कर सकता है, कभी भी इस बारे में चिंता किए बिना कि वे गतिशील रूप से कैसे अपडेट करेंगे, चाहे वह कितना भी जटिल या संरचनात्मक रूप से परिवर्तनशील हो।
उन दिनों में, मुझे दृश्य वस्तुओं के बीच हस्तक्षेप के बारे में चिंता करने की ज़रूरत थी, ताकि किसी को मिटा देने से दूसरों को नुकसान न पहुंचे। हालांकि, अब मैं विंडोज कंट्रोल के साथ तकनीक का उपयोग करता हूं, और मैं विंडोज को मुद्दों को प्रस्तुत करने का ध्यान रखता हूं।
तो इससे क्या हासिल होता है? इसका मतलब है कि मैं नियंत्रणों को चित्रित करने के लिए एक प्रक्रिया लिखकर एक संवाद का निर्माण कर सकता हूं, और मुझे वास्तव में नियंत्रण वस्तुओं को याद रखने या उन्हें अपडेट करने से निपटने, या उन्हें प्रकट करने / गायब होने / शर्तों को वारंट के रूप में स्थानांतरित करने के बारे में चिंता करने की आवश्यकता नहीं है। परिणाम बहुत छोटा और सरल संवाद स्रोत कोड है, परिमाण के एक क्रम के बारे में, और गतिशील लेआउट जैसी चीजें या नियंत्रण की संख्या में परिवर्तन या सरणियों या नियंत्रणों के ग्रिड तुच्छ हैं। इसके अलावा, एक संपादन क्षेत्र जैसे नियंत्रण, संपादन डेटा के लिए तुच्छ रूप से बाध्य हो सकता है और यह हमेशा सही साबित होगा, और मुझे कभी भी इसकी घटनाओं से नहीं जूझना पड़ेगा। एक अनुप्रयोग स्ट्रिंग चर के लिए एक संपादन क्षेत्र में लाना एक-पंक्ति संपादित करना है।
- यह समझना मुश्किल क्यों है?
मुझे समझाने के लिए सबसे कठिन जो मिला है वह यह है कि सॉफ्टवेयर के बारे में अलग तरह से सोचने की आवश्यकता है। प्रोग्रामर सॉफ्टवेयर के ऑब्जेक्ट-एक्शन दृश्य के प्रति इतनी दृढ़ता से वचनबद्ध हैं कि वे जानना चाहते हैं कि वस्तुएं क्या हैं, कक्षाएं क्या हैं, वे प्रदर्शन कैसे "निर्माण" करते हैं, और वे घटनाओं को कैसे संभालते हैं, कि यह एक चेरी लेता है उनमें से विस्फोट करने के लिए बम। मैं यह बताने की कोशिश करता हूं कि वास्तव में क्या मायने रखता है जो आपको कहने की जरूरत है?कल्पना कीजिए कि आप एक डोमेन-विशिष्ट भाषा (डीएसएल) का निर्माण कर रहे हैं, जहाँ आप सभी को यह करने की आवश्यकता है कि यह बताएं कि "मैं चर ए को यहाँ संपादित करना चाहता हूँ, चर बी को और वहाँ नीचे चर सी" और यह जादुई रूप से आपके लिए इसका ख्याल रखेगा। । उदाहरण के लिए, Win32 में संवादों को परिभाषित करने के लिए यह "संसाधन भाषा" है। यह पूरी तरह से अच्छा डीएसएल है, सिवाय इसके कि यह काफी दूर तक नहीं जाता है। यह मुख्य प्रक्रियात्मक भाषा में "जीवित" नहीं है, या आपके लिए घटनाओं को संभालता है, या इसमें लूप / सशर्त / सबरूटीन्स शामिल हैं। लेकिन इसका मतलब अच्छी तरह से है, और डायनामिक डायलॉग काम खत्म करने की कोशिश करता है।
तो, सोचने की अलग-अलग विधा है: किसी प्रोग्राम को लिखने के लिए, आप सबसे पहले एक उपयुक्त डीएसएल को खोजते हैं (या खोजते हैं), और अपने प्रोग्राम को जितना संभव हो उतना कोड करें। इसे उन सभी वस्तुओं और कार्यों से निपटने दें जो केवल कार्यान्वयन के लिए मौजूद हैं।
यदि आप वास्तव में अंतर निष्पादन को समझना चाहते हैं और इसका उपयोग करना चाहते हैं, तो कुछ मुश्किल मुद्दे हैं जो आपको यात्रा कर सकते हैं। मैंने एक बार इसे लिस्प मैक्रोज़ में कोडित किया था , जहां ये मुश्किल बिट्स आपके लिए संभाले जा सकते थे, लेकिन "सामान्य" भाषाओं में इसे नुकसान से बचने के लिए कुछ प्रोग्रामर अनुशासन की आवश्यकता होती है।
खेद है कि इतनी लंबी-चौड़ी हो गई। अगर मुझे समझ में नहीं आया है, अगर आप इसे इंगित करेंगे तो मैं इसकी सराहना करूंगा और मैं इसे ठीक करने की कोशिश कर सकता हूं।
जोड़ा गया:
में जावा घुमाओ , वहाँ एक उदाहरण कार्यक्रम TextInputDemo कहा जाता है। यह एक स्थिर संवाद है, जिसमें 270 लाइनें (50 राज्यों की सूची की गिनती नहीं) ले रही हैं। डायनामिक डायलॉग्स (MFC में) यह लगभग 60 लाइनें है:
#define NSTATE (sizeof(states)/sizeof(states[0]))
CString sStreet;
CString sCity;
int iState;
CString sZip;
CString sWholeAddress;
void SetAddress(){
CString sTemp = states[iState];
int len = sTemp.GetLength();
sWholeAddress.Format("%s\r\n%s %s %s", sStreet, sCity, sTemp.Mid(len-3, 2), sZip);
}
void ClearAddress(){
sWholeAddress = sStreet = sCity = sZip = "";
}
void CDDDemoDlg::deContentsTextInputDemo(){
int gy0 = P(gy);
P(www = Width()*2/3);
deStartHorizontal();
deStatic(100, 20, "Street Address:");
deEdit(www - 100, 20, &sStreet);
deEndHorizontal(20);
deStartHorizontal();
deStatic(100, 20, "City:");
deEdit(www - 100, 20, &sCity);
deEndHorizontal(20);
deStartHorizontal();
deStatic(100, 20, "State:");
deStatic(www - 100 - 20 - 20, 20, states[iState]);
if (deButton(20, 20, "<")){
iState = (iState+NSTATE - 1) % NSTATE;
DD_THROW;
}
if (deButton(20, 20, ">")){
iState = (iState+NSTATE + 1) % NSTATE;
DD_THROW;
}
deEndHorizontal(20);
deStartHorizontal();
deStatic(100, 20, "Zip:");
deEdit(www - 100, 20, &sZip);
deEndHorizontal(20);
deStartHorizontal();
P(gx += 100);
if (deButton((www-100)/2, 20, "Set Address")){
SetAddress();
DD_THROW;
}
if (deButton((www-100)/2, 20, "Clear Address")){
ClearAddress();
DD_THROW;
}
deEndHorizontal(20);
P((gx = www, gy = gy0));
deStatic(P(Width() - gx), 20*5, (sWholeAddress != "" ? sWholeAddress : "No address set."));
}
जोड़ा गया:
कोड के लगभग 40 लाइनों में अस्पताल के मरीजों की एक सरणी को संपादित करने के लिए उदाहरण कोड है। लाइनें 1-6 "डेटाबेस" को परिभाषित करती हैं। लाइनें 10-23 यूआई की समग्र सामग्री को परिभाषित करती हैं। लाइनों 30-48 एक मरीज के रिकॉर्ड को संपादित करने के लिए नियंत्रण को परिभाषित करते हैं। ध्यान दें कि कार्यक्रम का रूप समय में घटनाओं की लगभग कोई सूचना नहीं है, जैसे कि यह सब करना था एक बार प्रदर्शन बनाएं। फिर, अगर विषयों को जोड़ा जाता है या हटा दिया जाता है या अन्य संरचनात्मक परिवर्तन होते हैं, तो इसे बस फिर से निष्पादित किया जाता है, जैसे कि इसे फिर से खरोंच से बनाया जा रहा है, सिवाय इसके कि डीईई वृद्धिशील अद्यतन के बजाय जगह लेता है। लाभ यह है कि आपको प्रोग्रामर को यूआई होने के वृद्धिशील अपडेट करने के लिए कोई ध्यान देने या कोई कोड लिखने की आवश्यकता नहीं है, और उन्हें सही गारंटी दी जाती है। यह लग सकता है कि यह पुन: निष्पादन एक प्रदर्शन समस्या होगी, लेकिन ऐसा नहीं है,
1 class Patient {public:
2 String name;
3 double age;
4 bool smoker; // smoker only relevant if age >= 50
5 };
6 vector< Patient* > patients;
10 void deContents(){ int i;
11 // First, have a label
12 deLabel(200, 20, “Patient name, age, smoker:”);
13 // For each patient, have a row of controls
14 FOR(i=0, i<patients.Count(), i++)
15 deEditOnePatient( P( patients[i] ) );
16 END
17 // Have a button to add a patient
18 if (deButton(50, 20, “Add”)){
19 // When the button is clicked add the patient
20 patients.Add(new Patient);
21 DD_THROW;
22 }
23 }
30 void deEditOnePatient(Patient* p){
31 // Determine field widths
32 int w = (Width()-50)/3;
33 // Controls are laid out horizontally
34 deStartHorizontal();
35 // Have a button to remove this patient
36 if (deButton(50, 20, “Remove”)){
37 patients.Remove(p);
37 DD_THROW;
39 }
40 // Edit fields for name and age
41 deEdit(w, 20, P(&p->name));
42 deEdit(w, 20, P(&p->age));
43 // If age >= 50 have a checkbox for smoker boolean
44 IF(p->age >= 50)
45 deCheckBox(w, 20, “Smoker?”, P(&p->smoker));
46 END
47 deEndHorizontal(20);
48 }
जोड़ा गया: ब्रायन ने एक अच्छा सवाल पूछा, और मुझे लगा कि इसका जवाब यहाँ के मुख्य पाठ में है:
@ माइक: मैं स्पष्ट नहीं हूँ कि क्या "अगर (डेबटन (50, 20," जोड़ें ")) {" कथन वास्तव में कर रहा है। डीबटन कार्य क्या करता है? इसके अलावा, क्या आपके मैक्रो या किसी चीज़ का उपयोग करने के लिए आपके फ़ोर / END लूप हैं? - ब्रायन
@ ब्रायन: हां, FOR / END और IF स्टेटमेंट्स मैक्रोज़ हैं। SourceForge परियोजना का पूर्ण कार्यान्वयन है। deButton एक बटन नियंत्रण रखता है। जब कोई भी उपयोगकर्ता इनपुट कार्रवाई करता है, तो कोड "कंट्रोल इवेंट" मोड में चलाया जाता है, जिसमें डीबटन यह पता लगाता है कि इसे दबाया गया था और यह दर्शाता है कि यह TRUE वापस करके दबाया गया था। इस प्रकार, "if (deButton (...)) {... एक्शन कोड ...} बटन का एक्शन कोड अटैच करने का एक तरीका है, बिना क्लोजर बनाए या ईवेंट हैंडलर लिखना। DD_THROW एक है। जब कार्रवाई की जाती है तो पास को समाप्त करने का तरीका क्योंकि कार्रवाई में संशोधित एप्लिकेशन डेटा हो सकता है, इसलिए रूटीन के माध्यम से "कंट्रोल इवेंट" को जारी रखना अमान्य है। यदि आप इसे लिखने वाले इवेंट हैंडलर से तुलना करते हैं, तो यह आपको उन लोगों को लिखने से बचाता है। और यह आपको किसी भी संख्या को नियंत्रित करने देता है।
जोड़ा गया: क्षमा करें, मुझे समझाना चाहिए कि "रखरखाव" शब्द से मेरा क्या मतलब है। जब प्रक्रिया को पहले (SHOW मोड में) निष्पादित किया जाता है, तो deButton एक बटन नियंत्रण बनाता है और FIFO में इसकी आईडी याद रखता है। बाद के पास (UPDATE मोड में) पर, डेबटन को FIFO से आईडी मिल जाती है, यदि आवश्यक हो तो इसे संशोधित करता है और इसे FIFO में वापस रख देता है। ERASE मोड में, यह इसे FIFO से पढ़ता है, इसे नष्ट कर देता है, और इसे वापस नहीं डालता है, जिससे इसे "कचरा एकत्रित करना" पड़ता है। इसलिए डेबटन कॉल पूरे जीवनकाल को नियंत्रण में रखता है, इसे एप्लिकेशन डेटा के साथ जोड़कर रखता है, यही कारण है कि मैं इसे "बनाए रखता हूं"।
चौथा मोड ईवेंट (या नियंत्रण) है। जब उपयोगकर्ता एक चरित्र टाइप करता है या एक बटन पर क्लिक करता है, तो उस घटना को पकड़ा जाता है और रिकॉर्ड किया जाता है, और फिर डिवॉन्टेंट्स प्रक्रिया को EVM मोड में निष्पादित किया जाता है। deButton को FIFO से अपने बटन नियंत्रण की आईडी मिलती है और पूछता है कि क्या यह नियंत्रण है जिसे क्लिक किया गया था। यदि ऐसा था, तो यह TRUE लौटाता है, इसलिए कार्रवाई कोड निष्पादित किया जा सकता है। यदि नहीं, तो यह केवल FALSE लौटाता है। दूसरी ओर, यह deEdit(..., &myStringVar)
पता लगाता है कि क्या ईवेंट उसके लिए था, और यदि ऐसा है तो इसे एडिट कंट्रोल को पास करता है, और फिर एडिट कंट्रोल के कंटेंट को myStringVar पर कॉपी करता है। इस और सामान्य अद्यतन प्रसंस्करण के बीच, myStringVar हमेशा संपादन नियंत्रण की सामग्री के बराबर होता है। इस तरह "बंधन" किया जाता है। यही विचार स्क्रॉल बार, सूची बॉक्स, कॉम्बो बॉक्स, किसी भी प्रकार के नियंत्रण पर लागू होता है जो आपको एप्लिकेशन डेटा को संपादित करने देता है।
यहाँ मेरे विकिपीडिया संपादन का लिंक दिया गया है: http://en.wikipedia.org/wiki/User:MikeDunlavey/Difex_Article