2010-07-02 15 views
54

के सभी सबक्लास में परिभाषित करने के लिए एक निर्माता को कैसे मजबूर कर सकता हूं मेरे पास एक अमूर्त वर्ग ए है जो अमूर्त तरीकों को परिभाषित करता है। इसका मतलब है कि, एक वर्ग के लिए अस्थिर होने के लिए, सभी अमूर्त विधि को लागू किया जाना है।मैं अपने अमूर्त वर्ग

मैं अपने सभी उप-वर्गों को पैरामीटर के रूप में 2 इंट्स के साथ एक कन्स्ट्रक्टर को कार्यान्वित करना चाहता हूं।

एक कन्स्ट्रक्टर घोषित करना मेरे उद्देश्य को हराता है, क्योंकि मैं सबक्लास में परिभाषित कन्स्ट्रक्टर चाहता हूं और मुझे कार्यान्वयन के बारे में कुछ भी पता नहीं है। इसके अलावा मैं एक कन्स्ट्रक्टर को अमूर्त होने की घोषणा नहीं कर सकता;

क्या ऐसा करने का कोई तरीका है?

जो मैं चाहता का उदाहरण:

चलें कहना है कि मैं एक मैट्रिक्स वर्ग के एपीआई को परिभाषित कर रहा हूँ। मेरी समस्या में, मैट्रिक्स उनके आयामों को बदल नहीं सकता है।

एक मैट्रिक्स बनाने के लिए, मुझे इसका आकार प्रदान करने की आवश्यकता है।

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

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

+0

यहां एक सुरुचिपूर्ण समाधान मिल सकता है: http://stackoverflow.com/questions/6028526/java-force-an-extending-class –

उत्तर

48

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

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

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

एक विकल्प एक कारखाने के लिए एक अलग इंटरफेस है:

interface MyClassFactory 
{ 
    MyClass newInstance(int x, int y); 
} 

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

+2

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

+0

@Dodecaplex: लेकिन क्या होगा यदि आप 'फिक्स्ड साइज़मैट्रिक्स' कार्यान्वयन बनाना चाहते हैं जो * हमेशा * 10 x 10 है? आप किसी भी तरह से * कंट्रोलर्स polymorphically कॉल नहीं कर सकते हैं, तो आप कार्यान्वयन को सीमित करने की कोशिश क्यों कर रहे हैं? –

+1

वैसे तो कार्यान्वयन मेरे एपीआई के अनुरूप नहीं होगा ... यदि उसके पास ऐसा करने का अच्छा कारण है, तो यह शून्य तर्क कन्स्ट्रक्टर और 2 तर्क कन्स्ट्रक्टर प्रदान करेगा जो 10x10 नहीं होने पर अपवाद उठाएगा। इसका मतलब है कि मैं अभी भी एक ही कार्यान्वयन और उसी आकार के खाली मैट्रिक्स (प्रभावी कार्यान्वयन को जानने के बिना) बनाने में सक्षम हूं, लेकिन अगर मैं इस कार्यान्वयन का उपयोग गैर 10x10 मैट्रिक्स के लिए करने का प्रयास करता हूं तो मुझे अपवाद मिलेगा । – dodecaplex

2

यदि आपको अपने इंटरफ़ेस में परिभाषित करने की आवश्यकता है तो कक्षाओं को लागू करने वाले आंतरिक प्रतिनिधित्व का उपयोग किया जाएगा, तो आप इसे गलत कर रहे हैं। कृपया encapsulation और data abstraction के बारे में पढ़ें।

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

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

+1

ठीक है, अगर मैं एक एन-आयाम अंतरिक्ष में एक बिंदु परिभाषित कर रहा हूं, तो मुझे यकीन है कि बिंदु एम-आयाम स्थान (एम! = एन) में मौजूद नहीं हो सकता है। इसलिए, मुझे ऐसा लगता है कि बिंदु कार्यान्वयन के बावजूद, अंतरिक्ष का आयाम बिंदु की एक आंतरिक विशेषता है। जहां तक ​​मैं यह कह सकता हूं कि encapsulation और डेटा abstraction है। यदि आयाम अनिवार्य रूप से प्रत्येक उदाहरण के लिए जाना जाता है, तो यह एक ऐसा निर्माता प्रदान करने के लिए सभी कार्यान्वयन की आवश्यकता है जो इस तर्क को लेता है। – dodecaplex

+0

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

3

आप नीचे कुछ ऐसा करने की कोशिश कर सकते हैं। कार्यान्वयन वर्ग में उचित तर्क के साथ कोई कन्स्ट्रक्टर नहीं है तो कन्स्ट्रक्टर अपवाद फेंक देगा।

यह मूर्खतापूर्ण है। ठीक और खराब की तुलना करें। दोनों कक्षाएं समान हैं, सिवाय इसके कि ठीक है आपकी आवश्यकता को पूरा करता है और इस प्रकार रनटाइम चेक पास करता है। इस प्रकार आवश्यकता को लागू करने से काउंटर-उत्पादक व्यस्त कार्य को बढ़ावा मिलता है।

एक बेहतर समाधान कुछ प्रकार की फैक्ट्री होगी।

abstract class RequiresConstructor 
{ 
    RequiresConstructor(int x, int y) throws NoSuchMethodException 
    { 
    super(); 
    System.out.println(this.getClass().getName()) ; 
    this.getClass(). getConstructor (int.class , int.class) ; 
    } 

    public static void main(String[] args) throws NoSuchMethodException 
    { 
    Good good = new Good (0, 0); 
    OK ok = new OK(); 
    Bad bad = new Bad(); 
    } 
} 

class Good extends RequiresConstructor 
{ 
    public Good(int x, int y) throws NoSuchMethodException 
    { 
    super(x, y) ; 
    } 
} 

class OK extends RequiresConstructor 
{ 
    public OK(int x, int y) throws NoSuchMethodException 
    { 
    super(x, y) ; 
    throw new NoSuchMethodException() ; 
    } 

    public OK() throws NoSuchMethodException 
    { 
    super(0, 0) ; 
    } 
} 

class Bad extends RequiresConstructor 
{ 
    public Bad() throws NoSuchMethodException 
    { 
    super(0, 0) ; 
    } 
} 
0

क्या सार वर्ग में एक सार तत्व है जो आपके पास पैरामीटर के लिए होगा। उदाहरण के लिए:

public abstract void setSize(int rows,int columns); 
2

एक छोटी सी थोड़ी देर हो चुकी है, लेकिन ...

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

import java.lang.reflect.Constructor; 

public abstract class Gaga { 
    public Gaga() { 
    boolean found = false; 
    try { 
     Constructor<?>[] constructors = getClass().getConstructors(); 
     for (Constructor<?> c : constructors) { 
     if (c.getParameterTypes().length==2) { 
      Class<?> class0 = c.getParameterTypes()[0]; 
      Class<?> class1 = c.getParameterTypes()[1]; 
      if ((class0.getName().equals("int") || class0.isAssignableFrom(Integer.class)) 
       && (class1.getName().equals("int") || class1.isAssignableFrom(Integer.class))) 
      found = true; 
     } 
     } 
    } catch (SecurityException e) 
    { 
     found = false; 
    } 

    if (!found) 
     throw new RuntimeException("Each subclass of Gaga has to implement a constructor with two integers as parameter."); 

    //... 
    } 

} 

:

मैं प्रतिबिंब का एक बड़ा दोस्त है क्योंकि यह पिछले दरवाजे के माध्यम से हैकिंग के स्वाद है नहीं कर रहा हूँ, लेकिन कभी कभी यह मदद करता है ...

इस उदाहरण पर एक नज़र डालें और एक परीक्षण वर्ग:

public class Test { 
    private class Gaga1 extends Gaga { 
    public Gaga1() { this(0, 0); } 
    public Gaga1(int x, Integer y) { } 
    } 

    private class Gaga2 extends Gaga { 

    } 

    public static void main(String[] args) 
    { 
    new Gaga1(); 
    new Gaga1(1, 5); 
    new Gaga2(); 
    System.exit(0); 
    } 
} 

मुख्य कार्य Gaga1 की वस्तुओं का निर्माण किया जाएगा में, लेकिन Gaga2 का निर्माण एक क्रम अपवाद फेंक देते हैं।

लेकिन आप यह सुनिश्चित नहीं कर सकते कि इस निर्माता को बुलाया जाता है - आप यह भी सुनिश्चित नहीं कर सकते कि यह वही काम कर रहा है जो आप चाहते हैं।

यह परीक्षण केवल तभी उपयोगी है जब आप प्रतिबिंब के साथ काम कर रहे हों।

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