कंस्ट्रक्टर या सेटर विधि का उपयोग करें?


16

मैं UI कोड पर काम कर रहा हूं, जहां मेरा एक Actionवर्ग है, कुछ इस तरह से -

public class MyAction extends Action {
    public MyAction() {
        setText("My Action Text");
        setToolTip("My Action Tool tip");
        setImage("Some Image");
    }
}

जब यह एक्शन क्लास बनाया गया था, तो यह बहुत हद तक मान लिया गया था कि यह Actionवर्ग अनुकूलन योग्य नहीं होगा (एक अर्थ में - इसका पाठ, टूलटिप या छवि कोड में कहीं भी नहीं बदली जाएगी)। अब, हमें कोड में कुछ स्थान पर एक्शन टेक्स्ट को बदलने की आवश्यकता है। इसलिए, मैंने अपने सहकर्मी को निर्माणकर्ता से हार्डकोड किए गए एक्शन टेक्स्ट को हटाने और इसे एक तर्क के रूप में स्वीकार करने का सुझाव दिया, ताकि हर कोई एक्शन टेक्स्ट को पारित करने के लिए मजबूर हो। नीचे इस कोड की तरह कुछ -

public class MyAction extends Action {
    public MyAction(String actionText) {
        setText(actionText);
        setTooltip("My Action tool tip"); 
        setImage("My Image"); 
    }
}

हालाँकि, वह सोचता है कि चूंकि setText()विधि आधार वर्ग की है, इसलिए इसे एक्शन इंस्टेंस बनाने के लिए लचीले ढंग से एक्शन टेक्स्ट को पास करने के लिए इस्तेमाल किया जा सकता है। इस तरह, मौजूदा MyActionवर्ग को बदलने की कोई आवश्यकता नहीं है । तो उसका कोड कुछ इस तरह दिखेगा।

MyAction action = new MyAction(); //this creates action instance with the hardcoded text
action.setText("User required new action text"); //overwrite the existing text.

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


1
जिस भाषा का आप उपयोग कर रहे हैं, वह निर्माणकर्ताओं को ओवरलोडिंग की अनुमति नहीं देती है?
Mat

1
मैं Java.So का उपयोग कर रहा हूँ, यह अनुमति देता है और मुझे लगता है कि इससे निपटने का एक तरीका हो सकता है
zswap

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

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

जवाबों:


15

मूल कोड के साथ मुझे जो एकमात्र लाभ दिखाई देता है, वह यह है कि उपयोगकर्ता टेक्स्ट सेट करने के बारे में बहुत अधिक सोच के बिना एक्शन क्लास बना सकता है।

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

मुझे दो स्पष्ट रास्ते दिखाई देते हैं:

  1. एक निर्माता पैरामीटर का उपयोग करें, जैसा कि आप सुझाव देते हैं। यदि आप वास्तव में चाहते हैं, तो आप पास nullया एक खाली स्ट्रिंग कर सकते हैं , लेकिन तब यह तथ्य कि आप एक पाठ नहीं दे रहे हैं स्पष्ट है बजाय निहित है। एक nullपैरामीटर के अस्तित्व को देखना आसान है और देखें कि इसमें कुछ सोचा गया था, लेकिन विधि कॉल की कमी को देखने के लिए इतना आसान नहीं है और यह निर्धारित करना है कि इस तरह की कमी जानबूझकर थी या नहीं। इस तरह के एक साधारण मामले के लिए, यह संभवतः वह दृष्टिकोण है जो मैं ले जाऊंगा।
  2. एक कारखाने / बिल्डर पैटर्न का उपयोग करें। यह इस तरह के एक सरल परिदृश्य के लिए ओवरकिल हो सकता है, लेकिन एक अधिक सामान्य मामले में यह बहुत लचीला है क्योंकि यह आपको किसी भी संख्या में मापदंडों को सेट करने की अनुमति देता है, और वस्तु की तात्कालिकता से पहले या उसके दौरान पूर्व-स्थितियों की जाँच करें (यदि वस्तु का निर्माण एक बड़ा ऑपरेशन है और / या वर्ग को एक से अधिक तरीकों से उपयोग किया जा सकता है, यह एक बड़ा लाभ हो सकता है )। विशेष रूप से जावा में यह एक सामान्य मुहावरा भी है, और आपके द्वारा उपयोग की जा रही भाषा और फ्रेमवर्क में निम्न स्थापित पैटर्न बहुत ही खराब चीज है।

10

कंस्ट्रक्टर ओवरलोडिंग यहां एक सरल और सीधा समाधान होगा:

public class MyAction extends Action {
    public MyAction(String actionText) {
        setText(actionText);
        setTooltip("My Action tool tip"); 
        setImage("My Image"); 
    }
    public MyAction() {
        this("My Action Text");
    }
}

यह .setTextबाद में कॉल करने से बेहतर है , क्योंकि इस तरह से कुछ भी अधिलेखित करने की आवश्यकता नहीं है, actionTextशुरुआत से ही इच्छित चीज हो सकती है।

जैसा कि आपका कोड विकसित होता है और आपको और भी अधिक लचीलेपन की आवश्यकता होगी (जो निश्चित रूप से होगा), आपको दूसरे उत्तर के लिए सुझाए गए कारखाने / बिल्डर पैटर्न से लाभ होगा।


जब वे दूसरी संपत्ति को अनुकूलित करना चाहते हैं तो क्या होता है?
केविन क्लाइन

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

6

एक धाराप्रवाह 'सेटटेक्स्ट' विधि जोड़ें:

public class MyAction ... {
  ...
  public MyAction setText(String text) { ... ; return this; }
}

MyAction a = new MyAction().setText("xxx");

इससे साफ क्या हो सकता है? यदि आप एक और अनुकूलन योग्य संपत्ति जोड़ने का निर्णय लेते हैं, तो कोई समस्या नहीं है।


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

मुझे धाराप्रवाह इंटरफेस पसंद है, खासकर बिल्डरों के लिए जो अपरिवर्तनीय वस्तुओं का उत्पादन करते हैं! जितने अधिक पैरामीटर, उतना बेहतर यह काम करता है। लेकिन इस प्रश्न में विशिष्ट उदाहरण को देखते हुए, मैं अनुमान लगा रहा हूं कि setText()एक्शन वर्ग पर परिभाषित किया गया है जो MyAction से विरासत में मिला है। यह पहले से ही एक शून्य वापसी प्रकार है।
GlenPeterson

1

जैसे केविन क्लाइन ने अपने जवाब में कहा, मुझे लगता है कि जाने का तरीका एक धाराप्रवाह एपीआई बनाना है । मैं केवल यह जोड़ना चाहूंगा कि धाराप्रवाह एपीआई बेहतर काम करता है जब आपके पास एक से अधिक संपत्ति हो जो आप उपयोग कर सकते हैं।

यह आपके कोड को अधिक पठनीय बना देगा, और मेरे दृष्टिकोण से और अधिक आसान और, अहम् , "सेक्सी" लिखना होगा।

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

 public class MyAction extends Action {
    private String _text     = "";
    private String _tooltip  = "";
    private String _imageUrl = "";

    public MyAction()
    {
       // nothing to do here.
    }

    public MyAction text(string value)
    {
       this._text = value;
       return this;
    }

    public MyAction tooltip(string value)
    {
       this._tooltip = value;
       return this;
    }

    public MyAction image(string value)
    {
       this._imageUrl = value;
       return this;
    }
}

और उपयोग इस तरह होगा:

MyAction action = new MyAction()
    .text("My Action Text")
    .tooltip("My Action Tool tip")
    .image("Some Image");

बुरा विचार, क्या होगा अगर वे पाठ या किसी भी चीज़ को महत्वपूर्ण बनाना भूल जाते हैं।
प्रखर

1

कंस्ट्रक्टर या बिल्डरों का उपयोग करने की सलाह सामान्य रूप से ठीक है, लेकिन, मेरे अनुभव में, एक्शन के लिए कुछ प्रमुख बिंदुओं को याद किया जाता है, जो

  1. संभवतः अंतर्राष्ट्रीयकरण की आवश्यकता है
  2. विपणन के अंतिम समय में बदलने की संभावना है।

मैं दृढ़ता से सुझाव देता हूं कि नाम, टूलटिप, आइकन आदि ... एक गुण फ़ाइल, XML, आदि से पढ़ें। उदाहरण के लिए, फ़ाइल-ओपन कार्रवाई के लिए, आप एक गुण में पारित कर सकते हैं और यह खोज करेगा

File.open.name=Open
File.open.tooltip=Open a file
File.open.icon=somedir/open.jpg

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

यह सिर्फ एक मोटी रूपरेखा है, पाठक के लिए बहुत कुछ बचा है ... नजरबंदी के अन्य उदाहरणों के लिए देखें।


0

निर्माता के अंदर सेटटेक्स्ट (एक्शनटेक्स्ट) या सेटटूलिप ("माय एक्शन टूल टिप") को कॉल करना बेकार है; यदि आप सीधे संबंधित फ़ील्ड को प्रारंभ करते हैं तो यह आसान है (और आप अधिक प्रदर्शन प्राप्त करते हैं):

    public MyAction(String actionText) {
        this.actionText = actionText;
    }

यदि आप MyAction संगत ऑब्जेक्ट के जीवन काल के दौरान एक्शनटाइट बदलते हैं, तो आपको एक सेटर विधि रखनी चाहिए; यदि सेटर विधि प्रदान किए बिना केवल कंस्ट्रक्टर में फ़ील्ड को इनिशियलाइज़ नहीं किया जाता है।

चूंकि टूलटिप और छवि स्थिरांक हैं, उन्हें स्थिरांक के रूप में मानते हैं; खेत हैं:

private (or even public) final static String TOOLTIP = "My Action Tooltip";

वास्तव में, जब सामान्य वस्तुओं (न कि सेम या कड़ाई से डेटा संरचनाओं का प्रतिनिधित्व करने वाले ऑब्जेक्ट) को डिजाइन करते हैं, तो यह बसने और पाने वालों को प्रदान करने के लिए एक बुरा विचार है, क्योंकि वे एक तरह से ब्रेक इनकैप्सुलेशन हैं।


4
किसी भी आधे-योग्य सक्षम कंपाइलर और JITTER को सेटटेक्स्ट () आदि कॉल को इनलाइन करना चाहिए, इसलिए एक असाइनमेंट करने के लिए फ़ंक्शन कॉल के बीच प्रदर्शन अंतर और फ़ंक्शन कॉल के स्थान पर असाइनमेंट होने के लिए, नगण्य होना चाहिए, और अधिक संभावना है शून्य से नहीं।
एक CVn

0

मुझे लगता है कि यह सच है अगर हम एक जेनेरिक एक्शन क्लास बनाने जा रहे हैं (जैसे कि अपडेट, जिसका इस्तेमाल कर्मचारी, विभाग ... अपडेट करने के लिए किया जाता है)। यह सब परिदृश्य पर निर्भर करता है। यदि एक विशिष्ट कार्रवाई (जैसे अपडेट कर्मचारी) वर्ग (एप्लिकेशन में कई जगह उपयोग किया जाता है - अपडेट कर्मचारी) एक ही पाठ, टूलटिप और छवि को आवेदन में हर स्थान पर रखने के इरादे से बनाया गया है (स्थिरता की दृष्टि से)। इसलिए टेक्स्ट, टूलटिप और इमेज के लिए डिफ़ॉल्ट टेक्स्ट, टूलटिप और इमेज प्रदान करने के लिए हार्डकॉन्डिंग की जा सकती है। अभी भी अधिक लचीलापन देने के लिए, इन्हें अनुकूलित करने के लिए, इसके पास समान सेटर विधियाँ होनी चाहिए। केवल 10% स्थानों को ध्यान में रखते हुए हमें इसे बदलना होगा। हर बार उपयोगकर्ता से कार्रवाई पाठ लेना एक ही कार्रवाई के लिए हर बार अलग पाठ का कारण बन सकता है। जैसे Like अपडेट एम्प ’, Emp अपडेट कर्मचारी’, loy कर्मचारी बदलें ’या loy कर्मचारी को संपादित करें’।


मुझे लगता है कि ओवरलोडेड कंस्ट्रक्टर को अभी भी समस्या का समाधान करना चाहिए। क्योंकि सभी "10%" मामलों में, आप पहले डिफ़ॉल्ट टेक्स्ट के साथ एक एक्शन बनाएंगे और फिर "सेटटेक्स्ट ()" विधि का उपयोग करके एक्शन टेक्स्ट को बदलेंगे। कार्रवाई का निर्माण करते समय उपयुक्त पाठ क्यों नहीं सेट करें।
zswap

0

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

उदाहरण के लिए, यदि MyAction वर्ग को निर्माण के बाद अपरिवर्तनीय माना जाता है (और संभवतः अन्य आरंभीकरण), तो इसके लिए सेटर विधि नहीं होनी चाहिए। यदि अधिकांश समय यह डिफ़ॉल्ट "माई एक्शन टेक्स्ट" का उपयोग करेगा, तो एक पैरामीटर रहित निर्माता होना चाहिए, साथ ही एक रचनाकार जो एक वैकल्पिक पाठ की अनुमति देता है। अब उपयोगकर्ता को 90% समय सही ढंग से कक्षा का उपयोग करने के लिए सोचने की आवश्यकता नहीं है। यदि उपयोगकर्ता को आमतौर पर पाठ के लिए कुछ विचार देना चाहिए , तो पैरामीटर रहित निर्माता को छोड़ दें। अब उपयोगकर्ता आवश्यक होने पर सोचने के लिए मजबूर होता है और एक आवश्यक कदम को नजरअंदाज नहीं कर सकता है।

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

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


0

निम्नलिखित प्रस्तावित समाधान में, सुपरक्लास सार है और सभी तीन सदस्यों को एक डिफ़ॉल्ट मान पर सेट किया गया है।

उपवर्ग के पास अलग-अलग निर्माणकर्ता हैं, इसलिए प्रोग्रामर इसे तुरंत कर सकता है।

यदि पहले कंस्ट्रक्टर का उपयोग किया जाता है, तो सभी सदस्यों के पास डिफ़ॉल्ट मान होंगे।

यदि दूसरे निर्माणकर्ता का उपयोग किया जाता है, तो आप एक्शनटाइटल मेंबर को एक प्रारंभिक मान देते हैं और अन्य दो सदस्यों को डिफ़ॉल्ट मान के साथ छोड़ते हैं ...

यदि तीसरे कंस्ट्रक्टर का उपयोग किया जाता है, तो आप एक्शनटेक्स्ट और टूलटिप के लिए एक नए मान के साथ इसे इंस्टाल करते हैं, डिफ़ॉल्ट वैल्यू के लिए इमेजुरल व्हिट छोड़कर ...

और इसी तरह।

public abstract class Action {
    protected String text = "Default action text";
    protected String toolTip = "Default action tool tip";
    protected String imageURl = "http://myserver.com/images/default.png";

    .... rest of code, I guess setters and getters
}

public class MyAction extends Action {


    public MyAction() {

    }

    public MyAction(String actionText) {
        setText(actionText);
    }

    public MyAction(String actionText, String toolTip_) {
        setText(actionText);
        setToolTip(toolTip_);   
    }

    public MyAction(String actionText, String toolTip_; String imageURL_) {
        setText(actionText);
        setToolTip(toolTip_);
        setImageURL(imageURL_);
    }


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