2016-04-04 16 views
23

में स्विंग के ऐड() जैसे अतिव्यापी तरीकों को कॉल करना मुझे पता है कि कन्स्ट्रक्टरों से ओवरराइड करने योग्य तरीकों को कॉल करना एक बुरा विचार है। लेकिन मैं यह भी देखता हूं कि यह स्विंग के साथ हर जगह किया जा रहा है, जहां add(new JLabel("Something")); जैसे कोड हर समय रचनाकारों में होते हैं।कन्स्ट्रक्टर

उदाहरण के लिए नेटबीन आईडीई लें। यह रचनाकारों में अतिसंवेदनशील कॉल के बारे में बहुत पसंद है। और फिर भी, जब यह स्विंग कोड उत्पन्न करता है, तो यह उन add() विधि को initializeComponents() विधि में कॉल करता है ... जिसे तब निर्माता से कहा जाता है! किसी समस्या को छिपाने और चेतावनी को अक्षम करने का एक अच्छा तरीका (नेटबीन में "एक निजी विधि नहीं है जो ओवरराइड करने योग्य विधियों को कन्स्ट्रक्टर" चेतावनी से बुलाया जाता है)। लेकिन वास्तव में समस्या को हल करने का कोई तरीका नहीं है।

यहां क्या हो रहा है? मैं इसे उम्र के लिए कर रहा हूं, लेकिन हमेशा इसके बारे में एक असहज महसूस कर रहा था। अतिरिक्त init() विधि (और इसे हर बार कॉल करने के लिए भूलना नहीं भूल रहा है, जो कि उबाऊ है) को छोड़कर स्विंग कंटेनर को शुरू करने का एक बेहतर तरीका है?

public class MyBasePanel extends JPanel { 
    public MyBasePanel() { 
     initializeComponents(); 
    } 

    private void initializeComponents() { 
     // layout setup omitted 
     // overridable call 
     add(new JLabel("My label"), BorderLayout.CENTER); 
    } 
} 

public class MyDerivedPanel extends MyBasePanel { 
    private final List<JLabel> addedLabels = new ArrayList<>(); 

    @Override 
    public void add(Component comp, Object constraints) { 
     super.add(comp); 
     if (comp instanceof JLabel) { 
      JLabel label = (JLabel) comp; 
      addedLabels.add(label); // NPE here 
     } 
    } 
} 

उत्तर

6

तारों घुमाओ घटकों से बचने के लिए एक साथ निर्माता में, आप बस किसी अन्य वस्तु के लिए तारों की जिम्मेदारी दे सकता है। उदाहरण के लिए, यदि आप एक फैक्टरी के तारों कर्तव्यों दे सकता है:

public class MyPanelFactory { 
    public MyBasePanel myBasePanel() { 
     MyBasePanel myBasePanel = new MyBasePanel(); 
     initMyBasePanel(myBasePanel); 
     return myBasePanel; 
    } 

    public MyDerivedPanel myDerivedPanel() { 
     MyDerivedPanel myDerivedPanel = new MyDerivedPanel(); 
     initMyBasePanel(myDerivedPanel); 
     return myDerivedPanel; 
    } 

    private void initMyBasePanel(MyBasePanel myBasePanel) { 
     myBasePanel.add(new JLabel("My label"), BorderLayout.CENTER); 
    } 
} 

या आप सब बाहर जाने के लिए और एक निर्भरता इंजेक्शन कंटेनर के साथ अपने सभी घुमाओ घटकों का दृष्टांत और कंटेनर के तारों को गति प्रदान कर सकते हैं। है

@Module 
public class MyPanelModule { 
    static class MyBasePanel extends JPanel { 
     private final JLabel myLabel; 

     MyBasePanel(JLabel myLabel) { 
      this.myLabel = myLabel; 
     } 

     void initComponents() { 
      this.add(myLabel, BorderLayout.CENTER); 
     } 
    } 

    static class MyDerivedPanel extends MyBasePanel { 
     private final List<JLabel> addedLabels = new ArrayList<>(); 

     MyDerivedPanel(JLabel myLabel) { 
      super(myLabel); 
     } 

     @Override 
     public void add(Component comp, Object constraints) { 
      super.add(comp); 
      if (comp instanceof JLabel) { 
       JLabel label = (JLabel) comp; 
       addedLabels.add(label); 
      } 
     } 
    } 

    @Provides MyBasePanel myBasePanel(@Named("myLabel") JLabel myLabel) { 
     MyBasePanel myBasePanel = new MyBasePanel(myLabel); 
     myBasePanel.initComponents(); 
     return myBasePanel; 
    } 

    @Provides MyDerivedPanel myDerivedPanel(@Named("myLabel") JLabel myLabel) { 
     MyDerivedPanel myDerivedPanel = new MyDerivedPanel(myLabel); 
     myDerivedPanel.initComponents(); 
     return myDerivedPanel; 
    } 

    @Provides @Named("myLabel") JLabel myLabel() { 
     return new JLabel("My label"); 
    } 
} 
-2

Netbeans समारोह निजी पैदा कर रहा है:

उदाहरण

यहाँ कोई बात बिगड़ जाए सकते हैं कि कैसे की एक अत्यंत काल्पनिक उदाहरण है।

private initializeComponents() {...} 

इस प्रकार विधि अतिसंवेदनशील नहीं है। केवल संरक्षित और सार्वजनिक विधियां अतिसंवेदनशील हैं।

एक अतिरिक्त फ़ंक्शन नेटबीन्स के नमूने के लिए आपके कोड को अधिक क्लीनर रखता है। लेकिन आम तौर पर आप कक्षाओं को शुरू करने के लिए निजी तरीकों का उपयोग कर सकते हैं।

इसके अलावा यदि आपके पास एकाधिक रचनाकार हैं तो प्रारंभिकरण के लिए एक अतिरिक्त विधि का उपयोग करना व्यावहारिक है।

class Foo { 

    int x,y; 
    String bar; 

    public Foo(x) { 
     this.x = x; 
     init(); 
    } 

    public Foo(y) { 
     this.y = y; 
     init(); 
    } 
    private void init() { 
     // .. something complicated or much to do 
     bar = "bla"; 
    } 
} 
+2

यह कोड क्लीनर रख सकता है, लेकिन यह इसे * सुरक्षित * नहीं बनाता है। इसके विपरीत, समस्या अब छिपी हुई है, लेकिन यह अभी भी वहां है। हालांकि init फ़ंक्शन निजी है, फिर भी यह 'कॉल() 'जैसे कार्यों को कॉल करता है, नहीं हैं। तो अगर कोई 'add() 'ओवरराइड करता है, तो आपको बिल्कुल वही समस्या होगी, केवल एक निजी फ़ंक्शन में छिपी हुई है! यह मेरे प्रश्न का मुद्दा है। –

+0

उदाहरण के लिए मेरा संपादन देखें। –

1

OOP सिद्धांतों में से एक:: यहाँ डैगर साथ एक उदाहरण है विरासत से अधिक रचना पसंद करते हैं। जब मैं एक स्विंग जीयूआई बनाता हूं तो मैं कभी भी स्विंग घटकों का विस्तार नहीं करता हूं, सिवाय इसके कि मैं एक नया सामान्य उद्देश्य स्विंग घटक (जैसे जेटीआरटेबल, जेजीआरएल, जे कैलेंडर इत्यादि) बना देता हूं।

तो मेरी कोड लगता है:

public class MyPanel { 
    private JPanel mainPanel; 
    public MyPanel() { 
     init(); 
    } 
    private void init() { 
      mainPanel = new JPanel(); 
    } 
    public Component getComponent() { 
     return mainPanel; 
    } 
} 

public class MyComposedPanel { 
    private JPanel mainPanel; 
    public MyComposedPanel() { 
     init(); 
    } 
    private void init() { 
      mainPanel = new JPanel(); 
      mainPanel.add(new MyPanel().getComponent()); 
    } 
    public Component getComponent() { 
     return mainPanel; 
    } 
} 

इस तरह एक नुकसान यह है: वहाँ कोई GUI बिल्डर जो इसका समर्थन करता है;)

+0

क्या यह वास्तव में एकमात्र नुकसान है? आप अपने घटक को कंटेनर में कैसे जोड़ते हैं? कोड 'frame.add (myPanel.getComponent()) जैसे कोड मेरे लिए अजीब लग रहा है। –

+1

मेरे लिए यह कोई नुकसान नहीं है। अगर मैं अपने ग्रहण के प्रस्ताव पॉप-अप में 100 से अधिक तरीकों को देखता हूं, तो मुझे अधिक नुकसान मिलता है, जो जेकंपोनेंट से प्राप्त होते हैं। –

+0

मुझे डेमेटर के सिद्धांत का उल्लंघन करने जैसा लगता है। जो कुछ भी मिलता है उसके साथ सीधे काम करके कॉम्पोनेंट() 'रिटर्न' आप "अजनबी से बात कर रहे हैं"। यदि आप संरचना का उपयोग करते हैं, तो घटक को encapsulated किया जाना चाहिए। यही है, अगर यह वास्तव में रचना है। आपका उदाहरण मेरे लिए बिल्डर पैटर्न की तरह दिखता है, जो एक बेहतर विचार है। –

0

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

class MyBasePanel extends JPanel { 

    public static MyBasePanel create() { 
     MyBasePanel panel = new MyBasePanel(); 
     panel.initializeComponents(); 
     return panel; 
    } 

    protected MyBasePanel() { 
    } 

    protected void initializeComponents() { 
     // layout setup omitted 
     // overridable call 
     add(new JLabel("My label"), BorderLayout.CENTER); 
    } 
} 

class MyDerivedPanel extends MyBasePanel { 

    private final List<JLabel> addedLabels = new ArrayList<>(); 

    public static MyDerivedPanel create() { 
     MyDerivedPanel panel = new MyDerivedPanel(); 
     panel.initializeComponents(); 
     return panel; 
    } 

    protected MyDerivedPanel() { 
    } 

    @Override 
    public void add(Component comp, Object constraints) { 
     super.add(comp); 
     if (comp instanceof JLabel) { 
      JLabel label = (JLabel) comp; 
      addedLabels.add(label); // no more NPE here 
     } 
    } 
} 
बेशक

, तब भी initializeComponents कॉल करने के लिए याद करने के लिए है जब subclassing, लेकिन कम से कम हर बार एक उदाहरण बनाया गया है! उचित रूप से प्रलेखित, यह दृष्टिकोण सरल और भरोसेमंद दोनों हो सकता है।

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