2010-05-29 17 views
12

वहां पहले से ही कर रहे हैं कई तो क्यों वहाँ सार स्थिर विधि/जैसे क्षेत्र नहीं है पर सवाल, लेकिन मैं के बारे में कैसे एक निम्नलिखित छद्म-कोड को लागू करने के बारे में जाना होगा सोच रहा हूँ:"सार स्थैतिक" विधि - कैसे?

class Animal { 
    abstract static int getNumberOfLegs(); // not possible 
} 

class Chicken inherits Animal { 
    static int getNumberOfLegs() { return 2; } 


class Dog inherits Animal { 
    static int getNumberOfLegs() { return 4; } 

यहाँ समस्या है : मान लीजिए कि मैं यह सुनिश्चित करना चाहता हूं कि प्रत्येक श्रेणी जो Animal को getNumberOfLegs() विधि (यानी लगभग एक इंटरफ़ेस की तरह) को छोड़कर, मैं चाहता हूं कि अमूर्त वर्ग सभी विधियों को आम तौर पर कई विधियों को लागू करने के लिए चाहता है, इसलिए शुद्ध इंटरफ़ेस यहां काम नहीं करता है)। getNumberOfLegs() स्पष्ट रूप से एक स्थिर विधि होना चाहिए (यह मानते हुए कि एक परिपूर्ण दुनिया में हम 'चिकन और कुत्तों को अपंग नहीं करते हैं तो getNumberOfLegs उदाहरण-निर्भर नहीं है)।

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

आम तौर पर इस स्थिति को लागू करने के बारे में कैसे जाते हैं?


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

Animal getModelAnimal(int numberOfLegs) { 
    if (numberOfLegs == Chicken.getNumberOfLegs()) return new Chicken(); 
    else if (numberOfLegs == Dog.getNumberOfLegs()) return new Dog(); 
} 

उत्तर

3

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

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

http://forums.sun.com/thread.jspa?threadID=597378

से

कृपया यह भी Why can't I define a static method in a Java interface?

+0

-1: आप आम तौर पर यह नहीं कह सकते हैं। अमूर्त विधि हमेशा गैर-समझ नहीं है (मेरी पोस्ट देखें)। – Simon

+0

इसे प्रतिबिंबित करने के लिए मेरे उत्तर को संपादित किया गया। –

+0

मेरा प्रश्न भाषा अज्ञेयवादी होने के लिए है (मैं पहले सी # में इसी तरह की समस्या में भाग गया)। मैं देख सकता हूं कि एक भाषा में कोई "अमूर्त स्थैतिक" संशोधक क्यों नहीं है, लेकिन मुझे यह देखने में अधिक दिलचस्पी है कि प्रश्न में मैंने जो समस्या बताई है उसे साफ तरीके से कैसे कार्यान्वित किया जा सकता है। – polyglot

0

को देखने यहां तक ​​कि अगर आप एक सार स्थिर विधि हो सकता था, आप इसे कैसे प्रयोग करेंगे? इस बारे में सोचें कि आप इसे कैसे कार्यान्वित करना चाहते हैं, इससे पहले कि आप इसका उपयोग कैसे करेंगे, क्योंकि आपके कार्यान्वयन को उपयोगों से मेल खाना चाहिए।

+0

@ डाउनवॉटर: लोगों को क्यों न बताएं कि मेरे उत्तर में समस्या क्या है? –

3

यह वास्तव में एक अच्छा बिंदु है और कभी-कभी abstract static वास्तव में गायब है। हालांकि, आजकल मेमोरी एक समस्या नहीं है, इसलिए आप निश्चित रूप से getNumberLegs() -method को एक इंस्टेंस विधि के रूप में कार्यान्वित कर सकते हैं।

यह कहकर कि स्थिर सार गैर-समझ में है, सच नहीं है। PHP अमूर्त स्थैतिक तरीकों की अनुमति देता है (this देखें) और आपके परिदृश्य से पता चलता है कि यह कुछ स्थितियों में उपयोगी हो सकता है।

यह भी कहना सही नहीं है कि static विधियों को ओवरराइड नहीं किया जा सकता है; final विधियों को ओवरराइड नहीं किया जा सकता है। जावा और सी #, static जैसी भाषाओं में final के साथ आता है। यही कारण है कि कई लोग मानते हैं कि static "ओवरराइड करने योग्य" के बराबर नहीं है।

के बारे में सी # में बात कर रहे (अपनी टिप्पणी को पढ़ने के बाद, मुझे लगता है कि आप "बात" सी #), आप (जावा में या जेनरिक और एनोटेशन) जेनरिक और विशेषताओं का उपयोग करने के लिए विचार कर सकते हैं:

public class Animal 
{ 
    public static int GetNumberOfLegs<T>() where T : Animal 
    { 
    //Get T's custom attribute "NumberOfLegs" and return its value 
    } 

    //EDIT: Added runtime-version of GetNumberOfLegs. 
    public static int GetNumberOfLegs(Type t) 
    { 
    //Get t's custom attribute "NumberOfLegs" and return its value 

    } 
} 

[NumberOfLegs(4)] 
public class Cat { ... }; 

यह आपको अनुमति देगा इसे तत्काल किए बिना प्रत्येक प्रकार के पैरों की संख्या प्राप्त करने के लिए। बस [NumberOfLegs(x)] विशेषता इंगित करना याद रखें। आपको संकलन समय (विधि के सामान्य संस्करण के लिए) के प्रकार को भी जानना होगा।

संपादित करें: मैंने GetNumberOfLegs() -method का रनटाइम संस्करण जोड़ा, जिसमें आप Type ऑब्जेक्ट पास कर सकते हैं (जावा के लिए Class होना चाहिए)। आपको इस मामले में रनटाइम पर एक प्रकार की जांच करनी होगी, यानी Type -/Class - Animal से प्राप्त विरासत को प्राप्त करें या फिर विशेषता/एनोटेशन में दिए गए मान को पुनर्प्राप्त करें।

उपयोग:

int numberOfLegs1 = Animal.GetNumberOfLegs<Cat>(); 
int numberOfLegs2 = Animal.GetNumberOfLegs(typeof(Cat)); //runtime version 
+0

PHP के साथ जावा/सी # की तुलना करना संतरे के साथ सेब की तुलना करना है .. – BalusC

+2

यह तुलना नहीं है ... मैं दिखा रहा हूं कि सार स्थिर स्थिर नहीं है। मैं एक सामान्य ओओपी अवधारणा को इंगित कर रहा हूं। – Simon

+0

क्षमा करें, लेकिन अपने आप से, सार स्थिर अभी भी बकवास है। इस उपयोग के मामले से आपको समझने के लिए आपको एक कस्टम विशेषता की आवश्यकता है। –

2

कैसे एक आम तौर पर इस स्थिति लागू करने के बारे जाते हैं?

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

abstract class Animal { 
    private int numberOfLegs; 

    public Animal(int numberOfLegs) { 
     this.numberOfLegs = numberOfLegs; 
    } 

    public int getNumberOfLegs() { 
     return numberOfLegs; 
    } 
} 

class Chicken extends Animal { 
    public Chicken() { 
     super(2); 
    } 
} 

class Dog extends Animal { 
    public Dog() { 
     super(4); 
    } 
} 

अद्यतन: अगर आपके अपडेट

संपादित के अनुसार: यहां बताया गया है कि मैं इस का उपयोग हो सकता है। (किसी भी तरह अब यह हास्यास्पद है, लेकिन ...) मान लें कि के पैरों की संख्या प्रत्येक जानवर अद्वितीय है, इसलिए मैं कुछ की तरह हो सकता है:

Animal getModelAnimal(int numberOfLegs) { 
    if (numberOfLegs == Chicken.getNumberOfLegs()) return new Chicken(); 
    else if (numberOfLegs == Dog.getNumberOfLegs()) return new Dog(); 
} 

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

+0

लेकिन 'getNumberOfLegs() 'अभी भी एक उदाहरण विधि है और मुझे यह पता लगाने के लिए कक्षाओं को तुरंत चालू करना है कि जानवर के कितने पैर हैं ... – polyglot

+0

मेरे उत्तर का अद्यतन देखें। – BalusC

+0

हालांकि 'getModelAnimal() 'विधि को पशु वर्ग में आवश्यक रूप से परिभाषित नहीं किया गया है। – polyglot

0

यह एक दिलचस्प सवाल है। मेरी राय में, "स्थैतिक अमूर्त" विधियों की शायद ही कभी आवश्यकता होती है, और हमेशा अच्छे विकल्प होते हैं।

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

और अधिक आम तौर पर, के संयोजन सार और स्थिर कोई मतलब नहीं (जावा में) सार के बाद से है बहुरूपता का तात्पर्य है, जबकि स्थिर कॉल पर सभी गैर बहुरूपी होते हैं, और काम संकलन समय पर जाना जाता वर्गों पर।

4

इस स्थिति को लागू करने के लिए आमतौर पर कैसे जाते हैं?

सामान्य समाधान विधि को विधि विधि में विधि बनाना है।

getNumberOfLegs() जाहिर होना चाहिए एक स्थिर विधि (यह मानते हुए कि एक आदर्श दुनिया हम न में ' चिकन और कुत्तों अपंग है तो getNumberOfLegs नहीं उदाहरण पर निर्भर है)।

यह जोरदार रूप से स्पष्ट नहीं है! हम एक परिपूर्ण दुनिया के लिए कार्यक्रम नहीं करते हैं, और असली दुनिया में चार पैर वाले जानवरों में कभी-कभी एक, दो, या तीन (या पांच) पैर होते हैं।

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

class AnimalDefinition { 
    public string getScientificName(); 
    public string getCommonName(); 
    public int getNumberOfLegs(); 
    public bool getIsAmphibious(); 
    // etc. 
} 

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

0

आप एक क्रम जाँच लें कि विधि अपने आधार वर्ग इसके कार्यान्वयन में एक अपवाद फेंक होने से कार्यान्वित किया जाता है cludge सकता है। यह बहुत मूल्यवान नहीं है, लेकिन शायद कुछ भी बेहतर नहीं है ...

0

यदि आप उन्हें बेस क्लास की सहायता में कॉल करते हैं तो सार विधियां समझ में आती हैं। ध्यान दें कि आपके उदाहरण में, आप polimorphism का बिल्कुल उपयोग नहीं कर रहे हैं। उदाहरण में की तरह कुछ किया जाना चाहिए:

(Animal)Dog.getNumberOfLegs() //cast Dog to Animal first 

वैसे भी पीएचपी तथाकथित लागू करता है "देर स्थिर बाइंडिंग" जो है आप

http://php.net/manual/en/language.oop5.late-static-bindings.php

के लिए शायद क्या देख रहे सी ++ इसी तरह की सुविधा में tamplates का प्रयोग कर प्राप्त किया जा सकता है और संकलन-समय polymorphism।

0

abstract static विधियां केवल उन भाषाओं में समझ में आती हैं जिनमें चर के वास्तविक प्रकार हो सकते हैं न कि केवल उदाहरण। (डेल्फी एक ऐसी भाषा है, सी # नहीं है, और मुझे नहीं लगता कि आप इसे जावा में भी कर सकते हैं)। इसका कारण यह है कि यदि आप संकलित समय पर जानते हैं कि आप किस वर्ग का उपयोग कर रहे हैं (जैसे कि आपके उदाहरण में), तो abstract होने की विधि का कोई कारण नहीं है, तो आपके पास प्रत्येक श्रेणी में static विधियां हो सकती हैं बातें। एकमात्र तरीका जिसमें आप संभवतः नहीं जानते कि आप किस प्रकार का उपयोग कर रहे हैं, यदि आप एक चर के लिए प्रकार असाइन कर सकते हैं, तो आप उन्हें चारों ओर पास कर सकते हैं (बस कक्षाओं के उदाहरणों की तरह) और अचानक सबकुछ वास्तव में समझ में आता है और उपयोगी होता है।

मुझे लगता है कि सबसे compilers/भाषाओं जो (और साथ ही प्रकार के उदाहरण) चर के बताए प्रकारों का समर्थन भी संकलक जादू के माध्यम से abstract static और virtual abstract तरीकों का समर्थन करने के लिए प्रबंधन, तो वे तो पसंद की अपनी भाषा में वास्तव में उपयोगी हो अगर वे समर्थित होना चाहिए।

+0

न केवल परिवर्तनीय प्रकार के साथ भाषाएं। एक और मामला यह है कि जब इस तरह की अमूर्त स्थिर विधि को अन्य विधि से बुलाया जाता है। आइए मान लें कि पशु विधियों में से एक 'Animal.getNumberOfLegs() 'कहता है। तो कुत्ते इस विधि में से एक तरीके से कॉल कर सकते हैं। चूंकि 'getNumberOfLegs() 'अमूर्त है' Animal.getNumberOfLegs() 'पशु के विधि शरीर के अंदर,' Dog.getNumberOfLegs()' को भेजा जा सकता है। – doc

+0

उस उदाहरण को कोई समझ नहीं आता है। गैर-स्थैतिक कॉल के हस्ताक्षर के आधार पर संकलक को दूसरे प्रकार के लिए स्थिर कॉल प्रेषित करने के बारे में जानना कैसा है? ऐसा नहीं है कि ये चीजें कैसे काम करती हैं। – Donnie

+0

मुझे लगता है कि स्थैतिक कॉल के लिए अतिरिक्त vtable नौकरी करना चाहिए। वैसे भी, यह केवल आरटीटीआई पर निर्भर करता है। PHP ऐसा कुछ करता है (हालांकि बिल्कुल नहीं)। – doc

0

एक और दृष्टिकोण जो मैं यहां देख सकता हूं वह एक अमूर्त फैक्ट्री बनाना है: यह सी # है, आपको चिकन का एक उदाहरण कई पैरों को जानने की आवश्यकता नहीं है। सिर्फ checken कारखाने विधि

abstract class AnimalFactory 
{ 
    public abstract Animal CreateAnimal(); 
    public abstract int GetLegs(); 

} 
abstract class Animal 
{ 

} 
internal class Chicken : Animal 
{ 

} 
class CreateChicken : AnimalFactory 
{ 
    public override Animal CreateAnimal() 
    { 
     return new Chicken(); 
    } 
    public override int GetLegs() 
    { 
     return 2; 
    } 

} 
0

आह्वान एक क्षण के लिए, मान "सार स्थिर तरीकों" की अनुमति है।

फिर अपने कोड का उपयोग कर, मैं इस जोड़ें: है जो

Animal modelAnimal; 
int numLegs; 

modelAnimal = this.getModelAnimal(4); // Got a dog 

numLegs = modelAnimal.getNumberOfLegs(); 
त्रुटि

मैं मिल जाएगा रूप modelAnimal एक कुत्ता वस्तु getNumberOfLegsपशु में वर्ग और नहीं कॉल करने के लिए कोशिश करेंगे कुत्ता कक्षा। स्थिर विधियों के लिए ओवरराइडिंग आप जानते हैं। इस स्थिति से बचने के लिए, डिजाइनरों में अमूर्त स्थैतिक तरीकों को शामिल नहीं किया गया है।

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