2009-12-14 6 views
11

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

// Defines myMethod 
public class Base { 
    protected void myMethod() {} 
} 

// Uses myMethod and then hides it. 
public class DerivedOne extends Base { 
    @Override 
    private void myMethod(); 
} 

// can't access myMethod. 
public class DerivedTwo extends DerivedOne { 

} 

क्या इसे पूरा करने का कोई तरीका है?

संपादित व्याख्या करने के लिए कारण है कि मैं यह करने के लिए करना चाहते हैं:

इस मामले में वर्ग संरचना एक डेटा हैंडलिंग और आयात संरचना है। यह टैब्यूलर डेटा से भरा पाठ फ़ाइलों को पढ़ता है और पार्स करता है और फिर उन्हें डेटाबेस में संग्रहीत करता है।

बेस क्लास बेस टेबल क्लास डेटाबेस प्रबंधन को प्रबंधित करने का प्रबंधन करती है। इसमें एक निश्चित मात्रा में कार्यक्षमता है जो सभी तालिका प्रकारों के लिए आम है - जैसे ही वे डेटाबेस में होते हैं, वे वर्दी बन जाते हैं।

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

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

मैं पूछता हूं क्योंकि, उदाहरण के रूप में मैंने जो कोड पोस्ट किया है वह अवैध है, वही अंत करने के लिए कुछ अन्य साधन हो सकते हैं। मैं पूछ रहा हूं कि क्या है।

शायद छिपाने का यह गलत तरीका है - मुझे वास्तव में क्या करने की ज़रूरत है, कुछ कार्यक्षमता का पर्दाफाश करना है जो कक्षा वर्ग के लिए पदानुक्रम में एक स्तर तक निजी वर्ग के लिए निजी होना चाहिए। छिपाने से यह पूरा हो जाएगा - लेकिन मैं देख सकता हूं कि छुपा कैसे एक समस्या होगी। क्या इसे करने का और कोई तरीका है?

+2

के बाद से DerivedOne एक बेस है, यह ऊपर बेस के अनुबंध के लिए होने चाहिए जिसे की है। वैसे, यही कारण है कि प्रतिनिधिमंडल (समग्र पैटर्न) अक्सर विरासत पर पसंद किया जाता है। –

+0

@Steve मुझे विश्वास नहीं है कि समग्र पैटर्न यहां काम करेगा। संक्षेप में मुझे केवल कुछ कार्यक्षमता प्रकट करने की आवश्यकता है जो बेस क्लास के लिए एक वर्ग में निजी होनी चाहिए जो एक स्तर ऊपर है। –

+0

मेरा जवाब अपडेट किया गया। – rsp

उत्तर

15

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

ऐसा लगता है कि आप क्लासिक ORM समस्या का वर्णन कर रहे हैं। फिर से इस पर नजर डालते हैं और अगर हम इसे सख्त अलावा अन्य अवधारणाओं पर फिर से मैप कर सकते हैं विरासत "एक है", क्योंकि मैं सच में लगता है कि आपकी समस्या को तकनीकी नहीं है देखते हैं, यह वैचारिक है:

तुमने कहा था:

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

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

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

"मध्यम वर्ग" यहां Data Mapper जैसा लगता है। इस वर्ग को की पिछली कक्षा का विस्तार करने की आवश्यकता नहीं है, इसे इसके संदर्भ में होना चाहिए, शायद कन्स्ट्रक्टर या एक इंटरफ़ेस के रूप में सेटटर पर इंजेक्शन दिया जाना चाहिए।

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

मैं स्पष्ट क्यों एक उच्च स्तरीय वर्ग डाटाबेस स्कीमा के ज्ञान (कम से कम है कि क्या वाक्यांश "तालिका के लेआउट को प्रारंभ" है मेरे लिए सुझाव देते हैं), लेकिन फिर लगता है नहीं कर रहा हूँ, अगर बीच के रिश्ते पहले दो वर्ग encapsulation ("has a"/"uses a") instead of inheritance ("is a") थे, मुझे नहीं लगता कि यह एक समस्या होगी।

+0

आप कुछ अच्छे अंक लाते हैं, और यह निश्चित रूप से मुझे कुछ सोचने के लिए देता है। मेरी समस्या यह है कि जिस स्थिति में मैं काम कर रहा हूं वह खुद को encapsulation के लिए उधार नहीं देता है। मुझे डर है कि मैं वास्तव में अधिक जानकारी नहीं दे सकता - यह नौकरी और स्वामित्व है और मैं वास्तव में दी गई राशि के बारे में थोड़ा चिंतित हूं। हालांकि, मैं आपकी अंतर्दृष्टि की सराहना करता हूं और मैं अपनी संरचना पर एक कठिन दूसरा नजर डालूंगा। –

+1

असल में अब मैंने अपनी संरचना पर वापस देखा है, ऐसा लगता है कि मेरा सवाल वास्तव में सोमवार से पैदा हुआ था-जल्दी-दोपहर नींद से वंचित-मस्तिष्क-असफल और पर्याप्त कैफीन नहीं। चूंकि यह उस विधि को बदलता है जिसे मैं ऊपरी स्तर के वर्गों से छिपाना चाहता था, अगर उन्हें इसे ओवरराइड करने की आवश्यकता होती तो उन्हें दिखाई देने का इरादा था। मुझे नहीं पता कि मैं अन्यथा क्यों सोच रहा था। किसी भी मामले में, भविष्य के डिजाइनों के लिए अंगूठे का अच्छा नियम ध्यान में रखना है। यदि कभी कोई छुपाता सोचता है तो जरूरी है - किसी का डिज़ाइन गलत है। Encapsulation देखो। विचारशील और विस्तृत उत्तर के लिए धन्यवाद। –

10

नहीं। मुझे यकीन है कि तुम क्यों कल्पना बोली चाहते हैं और फिर वहाँ क्या कल्पना का कहना है के विपरीत करने के लिए कोई रास्ता नहीं है, तो पूछना नहीं कर रहा हूँ ...

शायद अगर तुम समझा क्यों आप चाहते हैं ऐसा करने के लिए, आप पर पर कुछ सुझाव प्राप्त कर सकते हैं।

+0

ठीक है, छुपाएं इसे समझाने का गलत तरीका था। हालांकि वह अंत को पूरा करेगा जो मुझे चाहिए। इसे समझाने का एक बेहतर तरीका दूसरी दिशा से है: मुझे बेस क्लास को क्लास में कुछ कार्यक्षमता का खुलासा करने की ज़रूरत है जो सीधे उससे प्राप्त होती है - लेकिन इसके ऊपर की कक्षाओं के लिए नहीं। –

6

किसी विधि को ओवरराइड करते समय आप इसे अधिक सार्वजनिक बना सकते हैं, अधिक निजी नहीं। तुम क्यों शब्द "सामान्य"

कि याद रखें का उपयोग मैं नहीं पता है, कम से कम से सबसे प्रतिबंधित करने के लिए आदेश देने:

public<protected<default<private 

हाँ, "protected" default की तुलना में एक कम प्रतिबंधक पहुँच संशोधक है (जब कोई संशोधक का उपयोग किया जाता है), ताकि आप ओवरराइडिंग विधि को protected के रूप में चिह्नित करने वाली डिफ़ॉल्ट विधि को ओवरराइड कर सकें, लेकिन इसके विपरीत नहीं।

सकता है: आप एक public एक के साथ एक protected विधि ओवरराइड कर सकते हैं।

नहीं कर सकते: आप एक protected एक के साथ एक public विधि ओवरराइड नहीं कर सकते।

+0

आप एक सुरक्षित पैकेज में 'संरक्षित 'के साथ' संरक्षित 'ओवरराइड कर सकते हैं, जो कि केवल अजीब है। आह, 'संरक्षित' "अजीब" है। –

+0

बेशक, आप ओवरराइड करने के लिए हमेशा एक ही एक्सेस संशोधक का उपयोग कर सकते हैं। एल्कन पहुंच के स्तर को बदलने के बारे में पूछ रहा है। – andandandand

+0

फिक्स्ड शब्द "सामान्य";) जब मेरा सिर कोड शब्दों में है तो मेरी ताकत नहीं है। मुझे इस नियम से अवगत है - मैं पूछ रहा हूं कि इसके आसपास काम करने का कोई तरीका है या नहीं। –

6

यदि आपने ऐसा किया है तो DerivedOne DerivedTwo के दृष्टिकोण से आधार नहीं होगा। इसके बजाय क्या आप चाहते हैं एक आवरण वर्ग

//Uses myMethod but keeps it hidden 
public class HiddenBase { 
    private final Base base = new Base(); 
    private void myMethod(); 
    public void otherMethod() {base.otherMethod();} 
} 

आप आधार इस तरह यद्यपि के संरक्षित तरीकों का उपयोग नहीं कर सकते हैं ...

+0

केवल 'निजी अंतिम आधार आधार = नया आधार(); '। –

+0

आह हाँ, धन्यवाद, मैं इसे ठीक कर दूंगा। – KernelJ

2

क्या आप का वर्णन आता है क्या protected पहुँच वर्ग के लिए है के करीब है, ली गई है कक्षाएं पहुंच सकती हैं, अन्य सभी नहीं कर सकते हैं।

यदि आप बेस क्लास से प्राप्त करते हैं तो आपके पास कोई समस्या नहीं हो सकती है, तो आप किसी समस्या को उत्पन्न कर सकते हैं, आप अपने वर्गों को विरासत में उपलब्ध कोड को सीधे सीधे कॉल करके, अपवाद फेंक कर दूसरों को अक्षम कर सकते हैं, जैसे कुछ:

// Uses myMethod and then hides it. 
public class DerivedOne extends Base { 
    @Override 
    public void myMethod() { 
     throw new IllegalStateException("Illegal access to myMethod"); 
    } 

    private void myPrivateMethod() { 
     super.myMethod(); 
    } 

} 

संपादित: अपने विस्तार जवाब देने के लिए, अगर मैं आप सही ढंग से समझ तुम आधार वर्ग जो मध्यम वर्ग में परिभाषित किया गया है के संदर्भ में व्यवहार निर्दिष्ट करने की जरूरत है। सार संरक्षित विधियां मध्यम वर्ग से प्राप्त कक्षाओं के लिए अदृश्य नहीं होंगी।

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

इंटरफ़ेस मध्यम वर्ग के अंदर घोंसले (स्थिर?) में लागू किया जाएगा।

public interface Specific { 
    public void doSomething(); 
} 

public class Base { 
    private final Specific specificImpl; 

    protected Base(Specific s) { 
     specificImpl = s; 
    } 

    public void doAlot() { 

     // ... 

     specificImpl.doSomething(); 

     // ... 
    } 
} 

public class Middle extends Base { 

    public Middle() { 
     super(new Impl()); 
    } 

    private Impl implements Specific { 

     public void doSomething() { 

      System.out.println("something done"); 
     } 
    } 
} 

public class Derived extends Middle { 

    // Access to doAlot() 
    // No access to doSomething() 
} 
+0

हम्म ... वह बदसूरत है। हाँ, संरक्षित करीब आता है, लेकिन वहां काफी नहीं है। हालांकि अच्छा विचार है। बस दिखाई देने के लिए जा रहे हैं। अगर मुझे बस रक्षा करने वाले लोगों को अनदेखा करने के लिए निर्देशित करना है जो ठीक है। थोड़ी उम्मीद थी कि सफाई के लिए केवल कार्यक्षमता के सीमित प्रकटीकरण का एक तरीका था। –

3

विरासत काम करता है क्योंकि हर जगह आप आधार वर्ग का उपयोग कर सकते हैं, आप भी यह उपवर्गों से एक का उपयोग कर सकते हैं: क्या मेरा मतलब है की तरह लग रहा है। व्यवहार अलग हो सकता है, लेकिन एपीआई नहीं है। अवधारणा को the Liskov substitution principle के रूप में जाना जाता है।

यदि आप विधियों तक पहुंच प्रतिबंधित करने में सक्षम थे, तो परिणामी वर्ग में एक ही एपीआई नहीं होगी और आप व्युत्पन्न वर्गों में से किसी एक के लिए बेस क्लास के उदाहरण का उपयोग करने में सक्षम नहीं होंगे, विरासत के लाभ को अस्वीकार करते हुए ।

क्या आप वास्तव में पूरा करने के लिए इंटरफेस के साथ किया जा सकता है चाहता हूँ:

interface IBase1 { 
} 

class Derived1 implements IBase1 { 
    public void myMethod() { 
    } 
} 

class Derived2 implements IBase1 { 
} 

class UseMe { 
    public void foo(IBase1 something) { 
    // Can take both Derived1 and Derived2 
    // Can not call something.myMethod() 
    } 
    public void foo(Derived1 something) { 
    something.myMethod(); 
    } 
    public void foo(Derived2 something) { 
    // not something.myMethod() 
    } 
} 
+0

अंतरफलक ऐसा नहीं करेंगे क्योंकि कार्यक्षमता है, केवल इंटरफ़ेस नहीं, बेस क्लास में लिखे गए सभी के लिए आम है। मैं वास्तव में क्या करने की कोशिश कर रहा हूं इसके बेहतर स्पष्टीकरण के लिए संपादन देखें। –

2

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

निम्नलिखित पर विचार:


package a; 

public class Base { 
    void myMethod() { 
     System.out.println("a"); 
    } 
} 

package a; 

public class DerivedOne extends Base { 
    @Override 
    void myMethod() { 
     System.out.println("b"); 
    } 
} 

package b; 

public class DerivedTwo extends a.DerivedOne { 
    public static void main(String... args) { 
     myMethod(); // this does not compile... 
    } 
} 

मैं अपने आप को अच्छा जा रहा है, अपने सहकर्मियों और किसी भी अन्य व्यक्ति की सिफारिश करेंगे कि समाप्त होता है अपने कोड को बनाए रखने के लिए; इससे बचने के लिए अपने वर्गों और इंटरफेस पर पुनर्विचार करें।

1

आप विधि अंतिम बनाने के लिए जब ओवरराइड यह

public class Base { 
protected void myMethod() {} 
} 

// Uses myMethod and then hides it. 
public class DerivedOne extends Base { 
@Override 
final protected void myMethod(); //make the method final 
} 


public class DerivedTwo extends DerivedOne { 
    // can't access myMethod here. 
}