एक विधि को कॉल करने का बेहतर तरीका क्या है जो केवल एक वर्ग के लिए उपलब्ध है जो एक इंटरफ़ेस को लागू करता है लेकिन दूसरे को नहीं?


11

मूल रूप से मुझे एक निश्चित स्थिति को देखते हुए विभिन्न कार्यों को निष्पादित करने की आवश्यकता है। मौजूदा कोड इस तरह से लिखा गया है

आधार इंटरफ़ेस

// DoSomething.java
interface DoSomething {

   void letDoIt(String info);
}

प्रथम श्रमिक वर्ग का क्रियान्वयन

class DoItThisWay implements DoSomething {
  ...
}

दूसरा श्रमिक वर्ग का कार्यान्वयन

class DoItThatWay implements DoSomething {
   ...
}

मुख्य वर्ग

   class Main {
     public doingIt(String info) {
        DoSomething worker;
        if (info == 'this') {
          worker = new DoItThisWay();
        } else {
          worker = new DoItThatWay();
        }
        worker.letDoIt(info)
     }

यह कोड ठीक काम करता है और समझने में आसान है।

अब, एक नई आवश्यकता के कारण, मुझे एक नई जानकारी को पारित करने की आवश्यकता है जो केवल समझ में आता है DoItThisWay

मेरा प्रश्न है: इस आवश्यकता को संभालने के लिए निम्न कोडिंग शैली अच्छी है।

नए वर्ग चर और विधि का उपयोग करें

// Use new class variable and method

class DoItThisWay implements DoSomething {
  private int quality;
  DoSomething() {
    quality = 0;
  }

  public void setQuality(int quality) {
    this.quality = quality;
  };

 public void letDoIt(String info) {
   if (quality > 50) { // make use of the new information
     ...
   } else {
     ...
   }
 } ;

}

यदि मैं इसे इस तरह से करता हूं, तो मुझे कॉल करने वाले के लिए समान परिवर्तन करने की आवश्यकता है:

   class Main {
     public doingIt(String info) {
        DoSomething worker;
        if (info == 'this') {
          int quality = obtainQualityInfo();
          DoItThisWay tmp = new DoItThisWay();
          tmp.setQuality(quality)
          worker = tmp;

        } else {
          worker = new DoItThatWay();
        }
        worker.letDoIt(info)
     }

क्या यह एक अच्छी कोडिंग शैली है? या मैं सिर्फ इसे डाल सकता हूं

   class Main {
     public doingIt(String info) {
        DoSomething worker;
        if (info == 'this') {
          int quality = obtainQualityInfo();
          worker = new DoItThisWay();
          ((DoItThisWay) worker).setQuality(quality)
        } else {
          worker = new DoItThatWay();
        }
        worker.letDoIt(info)
     }

19
सिर्फ qualityकंस्ट्रक्टर में पास क्यों नहीं DoItThisWay?
डेविड अरनो

मुझे शायद अपने प्रश्न को संशोधित करने की आवश्यकता है ... क्योंकि प्रदर्शन के कारण के निर्माण में DoItThisWayऔर DoItThatWayएक बार के निर्माण में किया जाता है MainMainलंबे समय तक रहने वाला वर्ग है और doingItइसे कई बार बार-बार कहा जाता है।
एंथनी कोंग

हां, अपने प्रश्न को अपडेट करना उस मामले में एक अच्छा विचार होगा।
डेविड अर्नो

क्या आपके कहने का अर्थ है कि वस्तु setQualityके जीवनकाल के दौरान विधि को कई बार कहा जाएगा DoItThisWay?
jpmc26

1
आपके द्वारा प्रस्तुत दो संस्करणों के बीच कोई प्रासंगिक अंतर नहीं है। एक तार्किक दृष्टिकोण से, वे एक ही काम करते हैं।
सेबस्टियन रेडल

जवाबों:


6

मैं मान रहा हूं कि qualityप्रत्येक letDoIt()कॉल के साथ सेट किए जाने की आवश्यकता है DoItThisWay()

मुद्दा मैं यहाँ उत्पन्न होने वाली देखना यह है: आप शुरू कर रहे हैं अस्थायी युग्मन (यानी क्या happends आप कॉल करना भूल जाते हैं setQuality()कॉल करने से पहले letDoIt()एक पर DoItThisWay?)। और लागू करने के लिए DoItThisWayऔर DoItThatWayडायवर्जन कर रहे हैं (एक को setQuality()बुलाया जाना चाहिए, दूसरा नहीं)।

हालांकि यह अभी मुद्दों का कारण नहीं हो सकता है, यह अंततः आपको परेशान करने के लिए वापस आ सकता है। एक और नज़र रखना सार्थक हो सकता है letDoIt()और विचार करें कि क्या गुणवत्ता की जानकारी infoआपको इसके माध्यम से गुजरने की आवश्यकता हो सकती है; लेकिन यह विवरण पर निर्भर करता है।


15

क्या यह एक अच्छी कोडिंग शैली है?

मेरे दृष्टिकोण से न तो आपका कोई संस्करण है। पहले कॉल करने setQualityसे पहले letDoItकहा जा सकता है कि एक अस्थायी युग्मन है । आप DoItThisWayएक व्युत्पन्न के रूप में देख रहे हैं DoSomething, लेकिन यह (कम से कम कार्यात्मक रूप से नहीं) है, यह एक तरह कुछ है

interface DoSomethingWithQuality {
   void letDoIt(String info, int quality);
}

यह Mainबल्कि कुछ ऐसा करना होगा

class Main {
    // omitting the creation
    private DoSomething doSomething;
    private DoSomethingWithQuality doSomethingWithQuality;

    public doingIt(String info) {
        DoSomething worker;
        if (info == 'this') {
            int quality = obtainQualityInfo();
            doSomethingWithQuality.letDoIt(info, quality);
        } else {
            doSomething.letDoIt(info);
        }
    }
}

दूसरी ओर आप मापदंडों को सीधे कक्षाओं में पास कर सकते हैं (यह मानते हुए कि यह संभव है) और निर्णय को सौंपें जो एक कारखाने में उपयोग करना है (यह उदाहरणों को फिर से विनिमेय बना देगा और दोनों से प्राप्त किया जा सकता है DoSomething)। यह Mainइस तरह दिखता है

class Main {
    private DoSomethingFactory doSomethingFactory;

     public doingIt(String info) {
         int quality = obtainQualityInfo();
         DoSomething doSomethingWorker = doSomethingFactory.Create(info, quality);
         doSomethingWorker.letDoIt();
     }
}

मुझे पता है कि आपने ऐसा लिखा है

क्योंकि प्रदर्शन के कारण DoItThisWay और DoItThatWay का निर्माण मेन के कंस्ट्रक्टर में एक बार किया जाता है

लेकिन आप उन हिस्सों को कैश कर सकते हैं जो कारखाने में बनाने और निर्माणकर्ता को पास करने के लिए महंगे हैं।


जब मैं उत्तर लिखता हूं, तो क्या आप अर्घ दे रहे हैं? हम इसी तरह के बिंदु बनाते हैं (लेकिन आपका बहुत अधिक व्यापक और वाक्पटु है);)
चारोनएक्स

1
@DocBrown हाँ, यह बहस का मुद्दा है, लेकिन चूंकि DoItThisWayकॉल करने से पहले letDoItइसे सेट करने के लिए गुणवत्ता की आवश्यकता होती है । मैं DoSomethingसभी डेरिवेटिव के लिए उसी तरह काम करने की उम्मीद करूंगा (गुणवत्ता पहले निर्धारित नहीं)। इसका कोई मतलब भी है क्या? बेशक यह एक प्रकार की धुँधली है, क्योंकि अगर हम setQualityकारखाने के तरीके से बुलाए जाते हैं, तो ग्राहक इस बारे में अज्ञेय होगा कि गुणवत्ता निर्धारित करनी है या नहीं।
पॉल केर्टशर

2
@DocBrown मुझे लगता है कि अनुबंध के लिए letDoIt()है (किसी भी अतिरिक्त जानकारी की कमी) "यदि आप मुझे प्रदान करते हैं तो मैं सही तरीके से निष्पादित कर सकता हूं (जो कुछ भी मैं करता हूं) String info।" setQuality()पहले से कॉल करने की आवश्यकता को कॉल करने के पूर्व शर्त को मजबूत करता है letDoIt(), और इस तरह एलएसपी का उल्लंघन होगा।
चारोनएक्स

2
@CharonX: यदि, उदाहरण के लिए, एक अनुबंध होगा जिसका अर्थ है कि " letDoIt" कोई अपवाद नहीं फेंकेगा, और "setQuality" को कॉल करने के लिए भूल जाएगा letDoItतो अपवाद को फेंक देगा , तो मैं सहमत हूं, इस तरह के कार्यान्वयन एलएसपी का उल्लंघन होगा। लेकिन वे मेरे लिए बहुत ही कृत्रिम धारणाओं की तरह दिखते हैं।
डॉक ब्राउन

1
यह एक अच्छा जवाब है। केवल एक चीज जो मैं जोड़ूंगा, वह यह है कि कोड बेस के लिए कितना बुरा अस्थायी अस्थायी युग्मन है। यह प्रतीत होता है decoupled घटकों के बीच एक छिपा हुआ अनुबंध है। सामान्य युग्मन के साथ, कम से कम यह स्पष्ट और आसानी से पहचाने जाने योग्य है। ऐसा करना अनिवार्य रूप से एक गड्ढा खोदकर पत्तियों के साथ कवर करना है।
जिमीजैम

10

मान लें qualityकि कंस्ट्रक्टर में पारित नहीं किया जा सकता है, और कॉल setQualityकी आवश्यकता है।

वर्तमान में, एक कोड स्निपेट पसंद है

    int quality = obtainQualityInfo();
    worker = new DoItThisWay();
    ((DoItThisWay) worker).setQuality(quality);

रास्ता बहुत छोटा है इसमें बहुत अधिक विचार निवेश करने के लिए। IMHO यह थोड़ा बदसूरत दिखता है, लेकिन वास्तव में समझने में मुश्किल नहीं है।

इस तरह के कोड स्निपेट बढ़ने पर समस्या उत्पन्न होती है और रिफैक्टरिंग के कारण आप ऐसा कुछ करते हैं

    int quality = obtainQualityInfo();
    worker = CreateAWorkerForThisInfo();
    ((DoItThisWay) worker).setQuality(quality);

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

हालांकि, मैं वास्तव में tmpएक बेहतर नाम दूंगा :

      int quality = obtainQualityInfo();
      DoItThisWay workerThisWay = new DoItThisWay();
      workerThisWay.setQuality(quality)
      worker = workerThisWay;

इस तरह के नामकरण से गलत कोड को गलत दिखने में मदद मिलती है।


tmp को और भी बेहतर तरीके से नाम दिया जा सकता है जैसे "workerThatUsesQuality"
user949300

1
@ user949300: IMHO यह एक अच्छा विचार नहीं है: मानने DoItThisWayसे अधिक विशिष्ट पैरामीटर मिलते हैं - आप जो सुझाव दे रहे हैं, उसके नाम को हर बार बदलना होगा। नाम vor चर का उपयोग करना बेहतर है जो ऑब्जेक्ट प्रकार को स्पष्ट करते हैं, न कि कौन से तरीकों के नाम उपलब्ध हैं।
डॉक ब्राउन

स्पष्ट करने के लिए, यह चर का नाम होगा, न कि कक्षा का नाम। मैं सहमत हूं कि सभी क्षमताओं को वर्ग नाम में रखना एक खराब विचार है। इसलिए मैं सुझाव दे रहा हूं कि workerThisWayकुछ ऐसा बन जाए usingQuality। उस छोटे से कोड स्निपेट में यह अधिक विशिष्ट होने के लिए सुरक्षित है। (और, अगर उनके डोमेन के भीतर एक बेहतर वाक्यांश है "useQuality" की तुलना में इसका उपयोग करें।
user949300

2

एक सामान्य इंटरफ़ेस जहां रनटाइम डेटा के आधार पर इनिशियलाइज़ेशन भिन्न होता है, आमतौर पर फ़ैक्ट्री पैटर्न में ही होता है।

DoThingsFactory factory = new DoThingsFactory(thingThatProvidesQuality);
DoSomething doSomething = factory.getDoer(info);

doSomething.letDoIt();

तब DoThingsFactory getDoer(info)कंक्रीट DoThingsWithQuality ऑब्जेक्ट को DoSomething इंटरफ़ेस में वापस करने से पहले विधि के अंदर गुणवत्ता की जानकारी प्राप्त करने और स्थापित करने के बारे में चिंता कर सकता है।

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