क्या एक ही वर्ग से निर्मित वस्तुओं में अद्वितीय विधि परिभाषाएं हो सकती हैं?


14

मुझे पता है कि यह एक अजीब सवाल लगता है, क्योंकि दो या दो से अधिक वस्तुओं को एक ही वर्ग साझा करने का मतलब यह है कि उनका व्यवहार समान है, अर्थात उनके तरीके समान हैं।

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

अगर मैं गलत नहीं हूँ, तो आप यह जावास्क्रिप्ट कर सकते हैं? इस सवाल के साथ, मैं पूछता हूं, कोई ऐसा क्यों करना चाहेगा?


9
तकनीकी शब्द "प्रोटोटाइप-आधारित" है। इसके लिए खोज करने से आपको ओओपी के इस स्वाद के बारे में बहुत कुछ मिलेगा। (ध्यान रखें कि बहुत सारे लोग ऐसी संरचनाओं को उचित "कक्षाएं" नहीं मानते हैं, ठीक है क्योंकि उनके पास एक समान गुण और विधियां नहीं हैं।)
किलियन फोथ

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

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

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

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

जवाबों:


9

अधिकांश (वर्ग-आधारित) OOP भाषाओं में विधियाँ प्रकार द्वारा तय की जाती हैं।

जावास्क्रिप्ट प्रोटोटाइप आधारित है, वर्ग आधारित नहीं है और इसलिए आप प्रति-इंस्टेंस बेस पर विधियों को ओवरराइड कर सकते हैं क्योंकि "क्लास" और ऑब्जेक्ट के बीच कोई कठिन अंतर नहीं है; वास्तव में, जावास्क्रिप्ट में एक "वर्ग" एक ऐसी वस्तु है जो उदाहरणों के लिए एक टेम्पलेट की तरह है कि कैसे काम करना चाहिए।

कोई भी भाषा जो प्रथम श्रेणी के कार्यों, स्काला, जावा 8, सी # (प्रतिनिधियों के माध्यम से) आदि की अनुमति देती है, जैसे आप प्रति-आवृत्ति विधि को ओवरराइड कर सकते हैं; आपको एक फ़ंक्शन प्रकार के साथ एक फ़ील्ड को परिभाषित करना होगा और फिर प्रत्येक उदाहरण में इसे ओवरराइड करना होगा।

स्काला की एक और सकारात्मकता है; स्काला में, आप ऑब्जेक्ट सिंग्लेटन्स बना सकते हैं (क्लास कीवर्ड के बजाय ऑब्जेक्ट कीवर्ड का उपयोग कर सकते हैं), इसलिए आप अपनी क्लास का विस्तार कर सकते हैं और विधियों को ओवरराइड कर सकते हैं, जिसके परिणामस्वरूप ओवरराइड्स के साथ उस बेस क्लास का एक नया उदाहरण बनता है।

क्यों कोई ऐसा करेगा? इसके दर्जनों कारण हो सकते हैं। यह हो सकता है कि विभिन्न क्षेत्र संयोजनों की अनुमति देने की तुलना में मेरे लिए व्यवहार को अधिक कसकर परिभाषित किया गया हो। यह बेहतर ढंग से कोड को डिकोड और व्यवस्थित भी रख सकता है। सामान्य तौर पर, मुझे लगता है कि ये मामले दुर्लभ हैं और अक्सर क्षेत्र के मूल्यों का उपयोग करते हुए अधिक सीधा समाधान है।


आपके पहले वाक्य का कोई मतलब नहीं है। वर्ग-आधारित OOP का निश्चित प्रकारों से क्या संबंध है?
बर्गी

मेरा मतलब है कि किसी पद्धति को जोड़ने या बदलने के लिए प्रति प्रकार के तरीके और परिभाषाएँ निश्चित हैं या दूसरे शब्दों में, आपको एक नया प्रकार बनाना होगा (जैसे उप-योग करके)।
बराबर है

@ बर्गी: वर्ग आधारित OOP में "वर्ग" और "प्रकार" शब्द का अनिवार्य रूप से एक ही मतलब है। चूंकि यह टाइप करने के लिए समझ में नहीं आता है कि "पूर्ण" मान रखने के लिए पूर्णांक टाइप करने के लिए यह भी मायने नहीं रखता है कि कर्मचारी के पास मान या तरीके हैं जो वर्ग कर्मचारी से संबंधित नहीं हैं।
स्लीवेटमैन

@ स्लेबेटमैन: मेरा मतलब था कि एक वर्ग-आधारित ओओपी भाषा जरूरी मजबूत, सांख्यिकीय रूप से लागू टाइपिंग नहीं है।
बरगी

@ बर्गी: यह ऊपर के उत्तर में "सबसे" का अर्थ है (अधिकांश का अर्थ है सभी नहीं)। मैं केवल आपके "यह क्या करना है" पर टिप्पणी कर रहा है।
स्लीवेटमैन

6

आपके प्रश्न के लिए प्रेरणा का अनुमान लगाना कठिन है, और इसलिए कुछ संभावित उत्तर आपकी वास्तविक रुचि को संबोधित कर सकते हैं या नहीं कर सकते हैं।

यहां तक ​​कि कुछ गैर-प्रोटोटाइप भाषाओं में भी इस प्रभाव को अनुमानित करना संभव है।

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

आप ऐसा क्यों करना चाहते हैं? जावा 8 लैम्ब्डा एक्सप्रेशन के साथ, मुझे लगता है कि कई बेहतरीन उपयोग के मामले चले जाते हैं। जावा के पुराने संस्करणों के साथ, कम से कम, यह तुच्छ, संकीर्ण-उपयोग वर्गों के प्रसार से बच सकता है। यही है, जब आपके पास संबंधित उपयोग-मामलों की एक बड़ी संख्या होती है, केवल एक छोटे से कार्यात्मक तरीके से भिन्न होने पर, आप उन्हें उस समय के व्यवहारगत अंतर के साथ लगभग ऑन-द-फ्लाई (लगभग) बना सकते हैं, जिस समय आपको इसकी आवश्यकता होती है।

कहा कि, पूर्व J8, यह अक्सर एक क्षेत्र या तीन में अंतर को स्थानांतरित करने के लिए, और उन्हें निर्माता में इंजेक्ट किया जा सकता है। J8 के साथ, निश्चित रूप से, विधि को स्वयं कक्षा में इंजेक्ट किया जा सकता है, हालांकि ऐसा करने का प्रलोभन हो सकता है जब एक और रीफैक्टरिंग क्लीनर हो सकता है (यदि ठंडा नहीं है)।


6

आपने किसी भी भाषा के लिए कहा है जो प्रति-इंस्टेंस विधियाँ प्रदान करती हैं। जावास्क्रिप्ट के लिए पहले से ही एक उत्तर है, तो आइए देखें कि यह आम लिस्प में कैसे किया जाता है, जहां आप EQL-special का उपयोग कर सकते हैं:

;; define a class
(defclass some-class () ())

;; declare a generic method
(defgeneric some-method (x))

;; specialize the method for SOME-CLASS
(defmethod some-method ((x some-class)) 'default-result)

;; create an instance named *MY-OBJECT* of SOME-CLASS
(defparameter *my-object* (make-instance 'some-class))

;; specialize SOME-METHOD for that specific instance
(defmethod some-method ((x (eql *my-object*))) 'specific-result)

;; Call the method on that instance
(some-method *my-object*)
=> SPECIFIC-RESULT

;; Call the method on a new instance
(some-method (make-instance 'some-class))
=> DEFAULT-RESULT

क्यों?

EQL-specializers उपयोगी है जब प्रेषण के अधीन तर्क के लिए एक प्रकार माना जाता है जिसके लिए eqlसमझ में आता है: एक संख्या, एक प्रतीक, आदि। आम तौर पर बोलना, आपको इसकी आवश्यकता नहीं है, और आपको बस कई उपवर्गों को परिभाषित करना होगा आपकी समस्या की जरूरत है। लेकिन कभी-कभी, आपको केवल एक पैरामीटर के अनुसार प्रेषण करने की आवश्यकता होती है, उदाहरण के लिए, एक प्रतीक: एक caseअभिव्यक्ति प्रेषण समारोह में ज्ञात मामलों तक सीमित होगी, जबकि किसी भी समय तरीकों को जोड़ा और हटाया जा सकता है।

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


5

आप इसे रूबी में सिंगलटन ऑब्जेक्ट्स का उपयोग करके भी कर सकते हैं:

class A
  def do_something
    puts "Hello!"
  end
end

obj = A.new
obj.do_something

def obj.do_something
  puts "Hello world!"
end

obj.do_something

पैदा करता है:

Hello!
Hello world!

उपयोग के लिए, यह वास्तव में है कि रूबी क्लास और मॉड्यूल तरीके कैसे करती है। उदाहरण के लिए:

def SomeClass
  def self.hello
    puts "Hello!"
  end
end

वास्तव helloमें Classऑब्जेक्ट पर एक सिंगलटन विधि को परिभाषित कर रहा है SomeClass


क्या आप मॉड्यूल और विस्तार-विधि के साथ अपना उत्तर देना चाहते हैं? (नई विधियों के साथ वस्तुओं का विस्तार करने के लिए बस कुछ अन्य तरीके दिखाने के लिए)?
knut

@knut: मुझे पूरा यकीन है कि extendवास्तव में सिर्फ ऑब्जेक्ट के लिए सिंगलटन क्लास बनाता है और फिर मॉड्यूल को सिंगलटन क्लास में इंपोर्ट करता है।
लिनक्स 19

5

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

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

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


1

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


0

आप C # और अन्य समान भाषाओं में ऐसा कुछ कर सकते हैं।

public class MyClass{
    public Func<A,B> MyABFunc {get;set;}
    public Action<B> MyBAction {get;set;}
    public MyClass(){
        //todo assign MyAFunc and MyBAction
    }
}

1
प्रोग्रामर वैचारिक प्रश्नों के बारे में हैं और चीजों की व्याख्या करने के लिए उत्तर अपेक्षित हैं। स्पष्टीकरण के बजाय कोड डंप फेंकना आईडीई से व्हाइटबोर्ड पर कोड कॉपी करने जैसा है: यह परिचित लग सकता है और यहां तक ​​कि कभी-कभी समझ में आता है, लेकिन यह अजीब लगता है ... बस अजीब है। व्हाइटबोर्ड में कंपाइलर नहीं है
gnat

0

वैचारिक रूप से, भले ही जावा जैसी भाषा में किसी वर्ग के सभी उदाहरणों में समान विधियाँ हों, लेकिन यह संभव है कि यह प्रकट हो सके, हालांकि वे अप्रत्यक्ष रूप से एक अतिरिक्त परत को जोड़कर नहीं रखते हैं, संभवतः नेस्टेड कक्षाओं के साथ संयोजन में।

उदाहरण के लिए, यदि कोई वर्ग Fooएक स्थिर अमूर्त नेस्टेड वर्ग को परिभाषित कर सकता है , QuackerBaseजिसमें एक विधि है quack(Foo), साथ ही कई अन्य स्थिर नेस्टेड कक्षाएं हैं QuackerBase, जिनमें से प्रत्येक की अपनी परिभाषा है quack(Foo), तो यदि बाहरी वर्ग का एक quackerप्रकार है QuackerBase, तो यह हो सकता है अपने नेस्टेड वर्गों में से किसी एक (संभवतः सिंगलटन) उदाहरण की पहचान करने के लिए उस फ़ील्ड को सेट करें। ऐसा करने के बाद, आह्वान उस वर्ग quacker.quack(this)की quackपद्धति को निष्पादित करेगा जिसका उदाहरण उस क्षेत्र को सौंपा गया है।

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


0

मेरा मानना ​​है कि रूबी, ग्रूवी और जावास्क्रिप्ट (और कई अन्य) जैसी "गतिशील" भाषा की परिभाषा है। डायनामिक रूप से (कम से कम भाग में) गतिशील रूप से फिर से परिभाषित करने की क्षमता को दर्शाता है कि मक्खी पर एक वर्ग उदाहरण कैसे व्यवहार कर सकता है।

यह सामान्य रूप से एक महान OO अभ्यास नहीं है, लेकिन कई गतिशील भाषा प्रोग्रामर OO सिद्धांतों के लिए उनकी सर्वोच्च प्राथमिकता नहीं है।

यह कुछ पेचीदा ऑपरेशनों को आसान बनाता है जैसे कि मंकी-पैचिंग जहाँ आप एक क्लास इंस्टेंस को ट्वीक कर सकते हैं ताकि आप बंद लाइब्रेरी के साथ इस तरह से बातचीत कर सकें कि वे फ़ॉरसी न करें।


0

मैं यह नहीं कह रहा हूं कि यह करना अच्छी बात है, लेकिन पायथन में यह बहुत संभव है। मैं अपने सिर के ऊपर से एक अच्छे उपयोग के मामले की बात नहीं कर सकता, लेकिन मुझे यकीन है कि वे मौजूद हैं।

    class Foo(object):
        def __init__(self, thing):
            if thing == "Foo":
                def print_something():
                    print "Foo"
            else:
                def print_something():
                    print "Bar"
            self.print_something = print_something

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