ऑब्जेक्ट ओरिएंटेड लेट बाइंडिंग


11

ऑब्जेक्ट ओरिएंटेड की एलन केस परिभाषा में यह परिभाषा है कि आंशिक रूप से मुझे समझ में नहीं आता है:

ओओपी टू मी का मतलब केवल मैसेजिंग, लोकल रिटेंशन और प्रोटेक्शन और स्टेट-प्रोसेस का छिपाना और सभी चीजों की चरम लेटबाइंडिंग है।

लेकिन "लेटबाइंडिंग" का क्या मतलब है? मैं इसे C # जैसी भाषा पर कैसे लागू कर सकता हूं? और यह इतना महत्वपूर्ण क्यों है?



2
C # में OOP शायद उस तरह का नहीं है जैसा OOP एलन के मन में था।
डॉक्टर ब्राउन

मैं आपसे सहमत हूँ, बिल्कुल ... उदाहरण किसी भी भाषा में स्वागत योग्य हैं
लुका ज़ूलियन 12

जवाबों:


14

"बाइंडिंग" एक विधि नाम को अमूल्य कोड के एक टुकड़े पर हल करने के अधिनियम को संदर्भित करता है। आमतौर पर, फ़ंक्शन कॉल को संकलन समय पर या लिंक समय पर हल किया जा सकता है। स्थैतिक बंधन का उपयोग करने वाली भाषा का एक उदाहरण C है:

int foo(int x);

int main(int, char**) {
  printf("%d\n", foo(40));
  return 0;
}

int foo(int x) { return x + 2; }

यहां, कॉल foo(40)को कंपाइलर द्वारा हल किया जा सकता है। यह शुरुआती कुछ अनुकूलन जैसे कि इनलाइनिंग की अनुमति देता है। सबसे महत्वपूर्ण लाभ हैं:

  • हम टाइप चेकिंग कर सकते हैं
  • हम अनुकूलन कर सकते हैं

दूसरी ओर, कुछ भाषाएं अंतिम संभव समय में फ़ंक्शन रिज़ॉल्यूशन को स्थगित कर देती हैं। एक उदाहरण पायथन है, जहां हम मक्खी पर प्रतीकों को फिर से परिभाषित कर सकते हैं:

def foo():
    """"call the bar() function. We have no idea what bar is."""
    return bar()

def bar():
    return 42

print(foo()) # bar() is 42, so this prints "42"

# use reflection to overwrite the "bar" variable
locals()["bar"] = lambda: "Hello World"

print(foo()) # bar() was redefined to "Hello World", so it prints that

bar = 42
print(foo()) # throws TypeError: 'int' object is not callable

यह देर से बाध्यकारी का एक उदाहरण है। हालांकि यह कठोर प्रकार की जाँच को अनुचित तरीके से करता है (प्रकार की जाँच केवल रनटाइम पर की जा सकती है), यह कहीं अधिक लचीली है और हमें उन अवधारणाओं को व्यक्त करने की अनुमति देती है जो स्थिर टाइपिंग या प्रारंभिक बाइंडिंग के दायरे में व्यक्त नहीं की जा सकती हैं। उदाहरण के लिए, हम रनटाइम पर नए कार्य जोड़ सकते हैं।

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

#define METHOD_CALL(object_ptr, name, ...) \
  (object_ptr)->vtable->name((object_ptr), __VA_ARGS__)

typedef struct {
    void (*sayHello)(const MyObject* this, const char* yourname);
} MyObject_VTable;

typedef struct {
    const MyObject_VTable* vtable;
    const char* name;
} MyObject;

static void MyObject_sayHello_normal(const MyObject* this, const char* yourname) {
  printf("Hello %s, I'm %s!\n", yourname, this->name);
}

static void MyObject_sayHello_alien(const MyObject* this, const char* yourname) {
  printf("Greetings, %s, we are the %s!\n", yourname, this->name);
}

static MyObject_VTable MyObject_VTable_normal = {
  .sayHello = MyObject_sayHello_normal,
};
static MyObject_VTable MyObject_VTable_alien = {
  .sayHello = MyObject_sayHello_alien,
};

static void sayHelloToMeredith(const MyObject* greeter) {
   // we have no idea what the VTable contents of my object are.
   // However, we do know it has a sayHello method.
   // This is dynamic dispatch right here!
   METHOD_CALL(greeter, sayHello, "Meredith");
}

int main() {
  // two objects with different vtables
  MyObject frank = { .vtable = &MyObject_VTable_normal, .name = "Frank" };
  MyObject zorg  = { .vtable = &MyObject_VTable_alien, .name = "Zorg" };

  sayHelloToMeredith(&frank); // prints "Hello Meredith, I'm Frank!"
  sayHelloToMeredith(&zorg); // prints "Greetings, Meredith, we are the Zorg!"
}

इस तरह की विधि खोज को "डायनेमिक प्रेषण" के रूप में भी जाना जाता है, और कहीं-कहीं शुरुआती बाध्यकारी और देर से बाध्यकारी के बीच भी। मैं गतिशील विधि प्रेषण को OOP प्रोग्रामिंग की केंद्रीय परिभाषित करने वाली संपत्ति मानता हूं, कुछ भी (जैसे एनकैप्सुलेशन, सबटिपिंग, ...) माध्यमिक होने के लिए। यह हमें हमारे कोड में बहुरूपता का परिचय देने में सक्षम बनाता है, और यहां तक ​​कि इसे फिर से जोड़ने के बिना कोड के एक टुकड़े में नया व्यवहार जोड़ने के लिए! C उदाहरण में, कोई भी एक नया व्यवहार्य जोड़ सकता है और उस vtable के साथ किसी ऑब्जेक्ट को पास कर सकता है sayHelloToMeredith()

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

उदाहरण के लिए, मैं programmers.stackexchange.se सर्वर से पूछ सकता हूं GET /questions/301919/। इसकी तुलना नोटेशन से करें programmers.get("/questions/301919/")। सर्वर इस अनुरोध को अस्वीकार कर सकता है या मुझे एक त्रुटि वापस भेज सकता है, या यह मुझे आपके प्रश्न की सेवा दे सकता है।

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

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

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


4

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

क्यों? क्योंकि यह प्रणाली के कुछ हिस्सों को स्वतंत्र रूप से बदलने की क्षमता को प्रोत्साहित करता है और इसे बढ़ने और व्यवस्थित रूप से बदलने की पुष्टि करता है।

उदाहरण के लिए, C # में आप obj1कुछ के लिए एक विधि में लिख सकते हैं obj2.doSomething()। इस पर आप obj1संवाद कर सकते हैं obj2। इसके लिए C # में होने के लिए, obj1एक निष्पक्ष बिट के बारे में जानने की जरूरत है obj2। इसकी कक्षा को जानना आवश्यक होगा। यह जाँच करेगा कि कक्षा में एक विधि है, doSomethingऔर उस पद्धति का एक संस्करण है जो शून्य पैरामीटर लेता है।

अब एक ऐसी प्रणाली की कल्पना करें जहाँ आप एक नेटवर्क या एक समान संदेश भेज रहे हैं। आप ऐसा कुछ लिख सकते हैं Runtime.sendMsg(ipAddress, "doSomething")। इस मामले में आपको उस मशीन के बारे में बहुत कुछ जानने की आवश्यकता नहीं है जिसके साथ आप संवाद कर रहे हैं; यह संभवतः आईपी के माध्यम से संपर्क किया जा सकता है और "doSomething" स्ट्रिंग प्राप्त होने पर कुछ करेगा। लेकिन अन्यथा आप बहुत कम जानते हैं।

अब कल्पना कीजिए कि वस्तुओं का संचार कैसे होता है। आप एक पते को जानते हैं और आप उस तरह के "पोस्टबॉक्स" फ़ंक्शन के साथ उस पते पर मनमाने संदेश भेज सकते हैं। इस मामले में, इसके obj1बारे में बहुत कुछ जानने की जरूरत नहीं है obj2, बस इसका पता है। यह समझने की भी जरूरत नहीं है कि यह समझता है doSomething

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

C # में, आप इसे एक तरह से दोहरा सकते हैं, एक ऐसा Runtimeवर्ग होने से जो किसी ऑब्जेक्ट रेफ और स्ट्रिंग को स्वीकार करता है और इस विधि को खोजने के लिए प्रतिबिंब का उपयोग करता है और इसे आह्वान करता है (यह तर्क और रिटर्न मान के साथ जटिल होने लगेगा लेकिन यह संभव होगा बदसूरत)।

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

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