क्या किसी विधि को कोड के एक निश्चित ब्लॉक के साथ शुरू करने का एक सुंदर तरीका है?


143

मेरे पास एक वर्ग है जहां हर विधि उसी तरह शुरू होती है:

class Foo {
  public void bar() {
    if (!fooIsEnabled) return;
    //...
  }
  public void baz() {
    if (!fooIsEnabled) return;
    //...
  }
  public void bat() {
    if (!fooIsEnabled) return;
    //...
  }
}

क्या fooIsEnabledकक्षा में हर सार्वजनिक पद्धति के लिए हिस्सा (और उम्मीद है कि हर बार नहीं लिखना) की आवश्यकता का एक अच्छा तरीका है ?


45
पहलू ओरिएंटेड प्रोग्रामिंग (विशेषकर सलाह से पहले ) में देखें।
सोटिरिओस डेलिमोनोलिस

15
इस बायलरप्लेट का उपयोग करने के लिए आपके पास कितने तरीके हैं? इससे पहले कि आप एओपी को शुरू करने के मार्ग पर जाएं, आप इस छोटे से दोहराया कोड के बारे में विचार कर सकते हैं। कभी-कभी थोड़ी सी कॉपी और पेस्ट सबसे सरल उपाय होता है।
भास्पेंक्टर

51
मुझे संदेह है कि एओपी ढांचे को सीखने की तुलना में आपके भविष्य के अनुचर को अतिरिक्त बॉयलर प्लेट के साथ खुशी होगी।
भास्करन

7
यदि कक्षा के प्रत्येक तरीके को कोड की पहली पंक्तियों में बहुत ही काम करना है तो हमारे पास एक बुरा डिज़ाइन है।
ट्यूलेंस कोर्डोवा

7
@ user1598390: यहां प्रश्न ऑफ-टॉपिक नहीं है, और प्रोग्रामर्स के दायरे के बारे में ऐसा कुछ नहीं है जो प्रश्न को विशेष रूप से सार्थक बनाता है।
रॉबर्ट हार्वे

जवाबों:


90

मुझे सुरुचिपूर्ण के बारे में पता नहीं है, लेकिन यहां जावा के बिल्ट-इन का उपयोग करते हुए एक कार्यान्‍वयन है, java.lang.reflect.Proxyजो इस बात को लागू करता है कि राज्‍य की Fooजाँच करके सभी विधि चालान शुरू होते हैं enabled

main तरीका:

public static void main(String[] args) {
    Foo foo = Foo.newFoo();
    foo.setEnabled(false);
    foo.bar(); // won't print anything.
    foo.setEnabled(true);
    foo.bar(); // prints "Executing method bar"
}

Foo इंटरफेस:

public interface Foo {
    boolean getEnabled();
    void setEnabled(boolean enable);

    void bar();
    void baz();
    void bat();

    // Needs Java 8 to have this convenience method here.
    static Foo newFoo() {
        FooFactory fooFactory = new FooFactory();
        return fooFactory.makeFoo();
    }
}

FooFactory वर्ग:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class FooFactory {

    public Foo makeFoo() {
        return (Foo) Proxy.newProxyInstance(
                this.getClass().getClassLoader(),
                new Class[]{Foo.class},
                new FooInvocationHandler(new FooImpl()));
    }

    private static class FooImpl implements Foo {
        private boolean enabled = false;

        @Override
        public boolean getEnabled() {
            return this.enabled;
        }

        @Override
        public void setEnabled(boolean enable) {
            this.enabled = enable;
        }

        @Override
        public void bar() {
            System.out.println("Executing method bar");
        }

        @Override
        public void baz() {
            System.out.println("Executing method baz");
        }

        @Override
        public void bat() {
            System.out.println("Executing method bat");
        }

    }

    private static class FooInvocationHandler implements InvocationHandler {

        private FooImpl fooImpl;

        public FooInvocationHandler(FooImpl fooImpl) {
            this.fooImpl = fooImpl;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getDeclaringClass() == Foo.class &&
                !method.getName().equals("getEnabled") &&
                !method.getName().equals("setEnabled")) {

                if (!this.fooImpl.getEnabled()) {
                    return null;
                }
            }

            return method.invoke(this.fooImpl, args);
        }
    }
}

जैसा कि दूसरों ने बताया है, यह आपको जरूरत के लिए ओवरकिल की तरह लगता है अगर आपको केवल कुछ ही तरीकों की चिंता करनी है।

उस ने कहा, निश्चित रूप से लाभ हैं:

  • चिंताओं का एक निश्चित पृथक्करण हासिल किया जाता है, क्योंकि Fooविधि के कार्यान्वयन को enabledचेक-कटिंग चिंता के बारे में चिंता करने की आवश्यकता नहीं है । इसके बजाय, विधि के कोड को केवल इस बारे में चिंता करने की आवश्यकता है कि विधि का प्राथमिक उद्देश्य क्या है, इससे अधिक कुछ नहीं।
  • एक निर्दोष डेवलपर के लिए Fooक्लास में एक नया तरीका जोड़ने और गलती से enabledचेक को जोड़ने के लिए "भूल" करने का कोई तरीका नहीं है । enabledजांच व्यवहार स्वचालित रूप से किसी भी नए जोड़े विधि द्वारा प्राप्त होती है।
  • यदि आपको एक और क्रॉस-कटिंग चिंता जोड़ने की आवश्यकता है, या यदि आपको enabledचेक को बढ़ाने की आवश्यकता है , तो यह सुरक्षित रूप से और एक स्थान पर करना बहुत आसान है।
  • यह अच्छा है कि आप इस AOP जैसा व्यवहार बिल्ट-इन जावा कार्यक्षमता के साथ प्राप्त कर सकते हैं। आपको कुछ अन्य ढांचे को एकीकृत करने के लिए मजबूर नहीं किया जाता है Spring, हालांकि वे निश्चित रूप से अच्छे विकल्प भी हो सकते हैं।

निष्पक्ष होने के लिए, निम्न में से कुछ हैं:

  • प्रॉक्सी कोड को लागू करने वाले कुछ कार्यान्वयन कोड बदसूरत हैं। कुछ लोग यह भी कहेंगे कि वर्ग की तात्कालिकता को रोकने के लिए आंतरिक कक्षाएं होना FooImplबदसूरत है।
  • यदि आप एक नई विधि जोड़ना चाहते हैं Foo, तो आपको 2 स्थानों में परिवर्तन करना होगा: कार्यान्वयन वर्ग और इंटरफ़ेस। कोई बड़ी बात नहीं है, लेकिन यह अभी भी थोड़ा और काम है।
  • प्रॉक्सी चालान मुफ्त नहीं हैं। एक निश्चित प्रदर्शन ओवरहेड है। हालांकि सामान्य उपयोग के लिए, यह ध्यान देने योग्य नहीं होगा। अधिक जानकारी के लिए यहाँ देखें ।

संपादित करें:

Fabian Streitel की टिप्पणी ने मुझे अपने उपरोक्त समाधान के साथ 2 परेशानियों के बारे में सोचने पर मजबूर कर दिया है, मैं मानता हूँ, मैं अपने बारे में खुश नहीं हूँ:

  1. मंगलाचरण हैंडलर "getEnabled" और "setEnabled" विधियों पर "सक्षम-चेक" को छोड़ने के लिए जादू के तार का उपयोग करता है। यह आसानी से टूट सकता है अगर विधि के नाम को फिर से दर्ज किया जाए।
  2. यदि कोई ऐसा मामला था, जिसमें नए तरीकों को जोड़ने की आवश्यकता है, जो "सक्षम-जांच" व्यवहार को प्राप्त नहीं करना चाहिए, तो डेवलपर के लिए यह गलत होना बहुत आसान हो सकता है, और बहुत कम से कम, इसका मतलब अधिक जादू जोड़ना होगा तार।

बिंदु # 1 को हल करने के लिए, और बिंदु # 2 के साथ समस्या को कम से कम करने के लिए, मैं एक एनोटेशन BypassCheck(या कुछ इसी तरह) बनाऊंगा जिसका उपयोग मैं Fooइंटरफ़ेस में उन तरीकों को चिह्नित करने के लिए कर सकता हूं जिनके लिए मैं "प्रदर्शन नहीं करना चाहता" सक्षम जांच "। इस तरह, मुझे जादू के तार की ज़रूरत नहीं है, और डेवलपर के लिए इस विशेष मामले में एक नई विधि को सही ढंग से जोड़ना बहुत आसान हो जाता है।

एनोटेशन समाधान का उपयोग करते हुए, कोड इस तरह दिखेगा:

main तरीका:

public static void main(String[] args) {
    Foo foo = Foo.newFoo();
    foo.setEnabled(false);
    foo.bar(); // won't print anything.
    foo.setEnabled(true);
    foo.bar(); // prints "Executing method bar"
}

BypassCheck एनोटेशन:

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BypassCheck {
}

Foo इंटरफेस:

public interface Foo {
    @BypassCheck boolean getEnabled();
    @BypassCheck void setEnabled(boolean enable);

    void bar();
    void baz();
    void bat();

    // Needs Java 8 to have this convenience method here.
    static Foo newFoo() {
        FooFactory fooFactory = new FooFactory();
        return fooFactory.makeFoo();
    }
}

FooFactory वर्ग:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class FooFactory {

    public Foo makeFoo() {
        return (Foo) Proxy.newProxyInstance(
                this.getClass().getClassLoader(),
                new Class[]{Foo.class},
                new FooInvocationHandler(new FooImpl()));
    }

    private static class FooImpl implements Foo {

        private boolean enabled = false;

        @Override
        public boolean getEnabled() {
            return this.enabled;
        }

        @Override
        public void setEnabled(boolean enable) {
            this.enabled = enable;
        }

        @Override
        public void bar() {
            System.out.println("Executing method bar");
        }

        @Override
        public void baz() {
            System.out.println("Executing method baz");
        }

        @Override
        public void bat() {
            System.out.println("Executing method bat");
        }

    }

    private static class FooInvocationHandler implements InvocationHandler {

        private FooImpl fooImpl;

        public FooInvocationHandler(FooImpl fooImpl) {
            this.fooImpl = fooImpl;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getDeclaringClass() == Foo.class
                    && !method.isAnnotationPresent(BypassCheck.class) // no magic strings
                    && !this.fooImpl.getEnabled()) {

                return null;
            }

            return method.invoke(this.fooImpl, args);
        }
    }
}

11
मुझे लगता है कि यह एक चतुर समाधान है लेकिन क्या आप वास्तव में इसका उपयोग करेंगे?
18

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

11
@ भास्कर: एक बहुत ही वैध प्रश्न। मैंने वास्तव में अपवाद हैंडलिंग, लॉगिंग, ट्रांजेक्शन हैंडलिंग आदि करने के लिए कई बार इसका उपयोग किया है, मैं मानता हूं कि छोटी कक्षाओं के लिए, यह ओवरकिल जैसा लगता है, और बहुत अच्छी तरह से हो सकता है। लेकिन अगर मैं उम्मीद करता हूं कि क्लास जटिलता में बहुत आगे बढ़ेगी, और सभी तरीकों से लगातार व्यवहार सुनिश्चित करना चाहता हूं, जैसा कि मैं करता हूं, तो मुझे यह समाधान बुरा नहीं लगता।
sstan

1
यहां 97% बुराई का हिस्सा नहीं है, लेकिन इस प्रॉक्सी वर्ग के प्रदर्शन के निहितार्थ क्या हैं?
corsiKa

5
@ कोरसीका: अच्छा सवाल। इसमें कोई संदेह नहीं है कि डायनेमिक प्रॉक्सिस का उपयोग करना डायरेक्ट मेथड कॉल की तुलना में धीमा है। हालांकि सामान्य उपयोग के लिए, प्रदर्शन ओवरहेड अगोचर होगा। संबंधित एसओ धागा यदि आप रुचि रखते हैं: जावा गतिशील प्रॉक्सी का प्रदर्शन लागत
sstan

51

बहुत सारे अच्छे सुझाव हैं .. आप अपनी समस्या पर प्रहार करने के लिए क्या कर सकते हैं, स्टेट पैटर्न में सोचें और उस पर अमल करें।

इस कोड स्निपेट पर एक नज़र डालें .. शायद यह आपको एक विचार के लिए मिलेगा। इस परिदृश्य में ऐसा लगता है कि आप ऑब्जेक्ट की आंतरिक स्थिति के आधार पर संपूर्ण विधियों के कार्यान्वयन को संशोधित करना चाहते हैं। कृपया याद रखें कि किसी वस्तु में विधियों का योग व्यवहार के रूप में जाना जाता है।

public class Foo {

      private FooBehaviour currentBehaviour = new FooEnabledBehaviour (); // or disabled, or use a static factory method for getting the default behaviour

      public void bar() {
        currentBehaviour.bar();
      }
      public void baz() {
        currentBehaviour.baz();
      }
      public void bat() {
        currentBehaviour.bat();
      }

      public void setFooEnabled (boolean fooEnabled) { // when you set fooEnabel, you are changing at runtime what implementation will be called.
        if (fooEnabled) {
          currentBehaviour = new FooEnabledBehaviour ();
        } else {
          currentBehaviour = new FooDisabledBehaviour ();
        }
      }

      private interface FooBehaviour {
        public void bar();
        public void baz();
        public void bat();
      }

      // RENEMBER THAT instance method of inner classes can refer directly to instance members defined in its enclosing class
      private class FooEnabledBehaviour implements FooBehaviour {
        public void bar() {
          // do what you want... when is enabled
        }
        public void baz() {}
        public void bat() {}

      }

      private class FooDisabledBehaviour implements FooBehaviour {
        public void bar() {
          // do what you want... when is desibled
        }
        public void baz() {}
        public void bat() {}

      }
}

उम्मीद है आप इसे पसंद करते हैं!

पीडी: राज्य पैटर्न का कार्यान्वयन है (संदर्भ के आधार पर रणनीति के रूप में भी जानता है .. लेकिन सिद्धांत केवल समान हैं)।


1
ओपी हर विधि की शुरुआत में कोड की एक ही पंक्ति को दोहराना नहीं चाहता है और आपके समाधान में प्रत्येक विधि की शुरुआत में कोड की एक ही पंक्ति को दोहराना शामिल है।
ट्यूलेंस कोर्डोवा

2
@ user1598390 वाष्पीकरण को दोहराने की कोई आवश्यकता नहीं है, FooEnabledBehaviour के अंदर आप यह मान रहे हैं कि इस ऑब्जेक्ट के क्लाइंट ने fooEnabled को सही पर सेट किया है, इसलिए चहकने की कोई आवश्यकता नहीं है। वही FooDisabledBehaviour वर्ग में जाता है। फिर से जांचें, इसमें कोड।
विक्टर

2
धन्यवाद @ bayou.io, कृपया ओपी जवाब तक प्रतीक्षा करें। मुझे लगता है कि समुदाय यहाँ नौकरी कर रहा है, यहाँ बहुत सारे अच्छे सुझाव हैं!
विक्टर

2
@Dyesdyes से सहमत मैं कुछ भी लेकिन वास्तव में तुच्छ वर्ग के लिए इसे लागू करने की कल्पना नहीं कर सकता। यह बहुत समस्याग्रस्त है, यह देखते हुए कि bar()में FooEnabledBehaviorऔर bar()में FooDisabledBehaviorदोनों के बीच शायद यह भी एक लाइन अलग से, एक ही कोड का एक बहुत कुछ साझा करते हैं। आप बहुत आसानी से कर सकते हैं, खासकर अगर इस कोड को जूनियर देवों (जैसे कि स्वयं) द्वारा बनाए रखा जाना था, बकवास की एक विशाल गड़बड़ी के साथ समाप्त होता है जो कि अकल्पनीय और अप्राप्य है। यह किसी भी कोड के साथ हो सकता है, लेकिन यह वास्तव में बहुत तेजी से पेंच करना इतना आसान लगता है। +1 हालांकि, अच्छा सुझाव है।
बजे क्रिस क्रेफ़िस जूल

1
मम्मम ... मैं लोगों को नहीं .. लेकिन पहले, टिप्पणियों के लिए धन्यवाद। मेरे लिए कोड का आकार एक समस्या नहीं है जब तक कि यह "साफ" और "पठनीय" न हो। मेरे पक्ष में मुझे तर्क देना चाहिए कि मैं किसी बाहरी वर्ग का उपयोग नहीं कर रहा हूं .. जिससे चीजों को अधिक सुलभ बनाना चाहिए। और अगर कुछ सामान्य व्यवहार है, तो हम इसे एक CommonBehaviourClass में एन्क्रिप्ट करें और जहां जरूरत हो, वहां प्रतिनिधि करें। GOF पुस्तक में (सीखने के लिए मेरी पसंदीदा पुस्तक नहीं, लेकिन अच्छी रेसिपी है) आपको यह उदाहरण मिला: en.wikipedia.org/wiki/… । कमोबेश यही काम मैं यहां कर रहा हूं।
विक्टर

14

हां, लेकिन यह थोड़ा सा काम है, इसलिए यह निर्भर करता है कि यह आपके लिए कितना महत्वपूर्ण है।

आप कक्षा को एक इंटरफ़ेस के रूप में परिभाषित कर सकते हैं, एक प्रतिनिधि कार्यान्वयन लिख सकते हैं, और फिर java.lang.reflect.Proxyइंटरफ़ेस को उन तरीकों से लागू करने के लिए उपयोग कर सकते हैं जो साझा भाग करते हैं और फिर प्रतिनिधि को सशर्त रूप से कॉल करते हैं।

interface Foo {
    public void bar();
    public void baz();
    public void bat();
}

class FooImpl implements Foo {
    public void bar() {
      //... <-- your logic represented by this notation above
    }

    public void baz() {
      //... <-- your logic represented by this notation above
    }

    // and so forth
}

Foo underlying = new FooImpl();
InvocationHandler handler = new MyInvocationHandler(underlying);
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
     new Class[] { Foo.class },
     handler);

आप MyInvocationHandlerइस तरह से कुछ देख सकते हैं (त्रुटि से निपटने और वर्ग मचान छोड़े गए, यह मानते हुए fooIsEnabledकि कहीं सुलभ है)

public Object invoke(Object proxy, Method method, Object[] args) {
    if (!fooIsEnabled) return null;
    return method.invoke(underlying, args);
}

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

गतिशील प्रॉक्सी कक्षाओं के विवरण के लिए जावा प्रलेखन देखें ।


14

यह सवाल पहलू-उन्मुख प्रोग्रामिंग से निकटता से संबंधित है । AspectJ जावा का AOP एक्सटेंशन है और आप इसे कुछ आइसपिरेशन पाने के लिए देख सकते हैं।

जहाँ तक मुझे पता है कि जावा में AOP का कोई प्रत्यक्ष समर्थन नहीं है। कुछ GOF पैटर्न हैं जो इससे संबंधित हैं, उदाहरण के लिए टेम्पलेट विधि और रणनीति लेकिन यह वास्तव में आपको कोड की लाइनों को नहीं बचाएगा।

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

public void checkBalance() {
    checkSomePrecondition();
    ...
    checkSomePostcondition();
}

हालांकि यह आपके मामले में फिट नहीं होगा क्योंकि आप फैक्टर-आउट कोड को वापस करने में सक्षम होना चाहेंगे checkBalance। मैक्रोज़ का समर्थन करने वाली भाषाओं में (जैसे C / C ++) आप मैक्रोज़ के रूप में परिभाषित कर सकते हैं checkSomePreconditionऔर checkSomePostconditionकंपाइलर के लागू होने से पहले ही उन्हें प्रीप्रोसेसर द्वारा बदल दिया जाएगा:

#define checkSomePrecondition \
    if (!fooIsEnabled) return;

जावा में यह बॉक्स से बाहर नहीं है। यह किसी को अपमानित कर सकता है लेकिन मैंने अतीत में दोहराए गए कोडिंग कार्यों को स्वचालित करने के लिए स्वचालित कोड पीढ़ी और टेम्पलेट इंजन का उपयोग किया था। यदि आप अपने जावा फ़ाइलों को एक उपयुक्त प्रीप्रोसेसर के साथ संकलित करने से पहले संसाधित करते हैं, उदाहरण के लिए, जिन्जा 2, आप सी में संभव है जैसा कुछ कर सकते हैं।

संभव शुद्ध जावा दृष्टिकोण

यदि आप एक शुद्ध जावा समाधान की तलाश में हैं, तो आपको जो मिल सकता है वह शायद संक्षिप्त नहीं होगा। लेकिन, यह अभी भी आपके कार्यक्रम के सामान्य भागों को प्रभावित कर सकता है और कोड दोहराव और बग से बच सकता है। आप ऐसा कुछ कर सकते हैं (यह कुछ प्रकार की रणनीति -inspired पैटर्न है)। ध्यान दें कि C # और Java 8 में, और अन्य भाषाओं में जिनमें फ़ंक्शंस को संभालना थोड़ा आसान है, यह दृष्टिकोण वास्तव में अच्छा लग सकता है।

public interface Code {
    void execute();
}

...

public class Foo {
  private bool fooIsEnabled;

  private void protect(Code c) {
      if (!fooIsEnabled) return;
      c.execute();
  }

  public void bar() {
    protect(new Code {
      public void execute() {
        System.out.println("bar");
      }
    });
  }

  public void baz() {
    protect(new Code {
      public void execute() {
        System.out.println("baz");
      }
    });
  }

  public void bat() {
    protect(new Code {
      public void execute() {
        System.out.println("bat");
      }
    });
  }
}

एक वास्तविक दुनिया के परिदृश्य का किंडा

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

यूजर इंटरफेस धागा कॉल RobotController.left, right, upया downउपयोगकर्ता बटन पर क्लिक करता है, लेकिन यह भी कहता है जब BaseController.tickनिजी करने के लिए फिर से सक्षम आदेश अग्रेषण करने के लिए, नियमित अंतराल पर DataLinkउदाहरण।

interface Code {
    void ready(DataLink dataLink);
}

class BaseController {
    private DataLink mDataLink;
    private boolean mReady = false;
    private Queue<Code> mEnqueued = new LinkedList<Code>();

    public BaseController(DataLink dl) {
        mDataLink = dl;
    }

    protected void protect(Code c) {
        if (mReady) {
            mReady = false;
            c.ready(mDataLink);
        }
        else {
            mEnqueue.add(c);
        }
    }

    public void tick() {
        byte[] frame = mDataLink.readWithTimeout(/* Not more than 50 ms */);

        if (frame != null && /* Check that it's an ACK frame */) {
          if (mEnqueued.isEmpty()) {
              mReady = true;
          }
          else {
              Code c = mEnqueued.remove();
              c.ready(mDataLink);
          }
        }
    }
}

class RobotController extends BaseController {
    public void left(float amount) {
        protect(new Code() { public void ready(DataLink dataLink) {
            dataLink.write(/* Create a byte[] that means 'left' by amount */);
        }});
    }

    public void right(float amount) {
        protect(new Code() { public void ready(DataLink dataLink) {
            dataLink.write(/* Create a byte[] that means 'right' by amount */);
        }});
    }

    public void up(float amount) {
        protect(new Code() { public void ready(DataLink dataLink) {
            dataLink.write(/* Create a byte[] that means 'up' by amount */);
        }});
    }

    public void down(float amount) {
        protect(new Code() { public void ready(DataLink dataLink) {
            dataLink.write(/* Create a byte[] that means 'down' by amount */);
        }});
    }
}

4
क्या यह सिर्फ सड़क को नीचे गिरा सकता है। कहने का तात्पर्य यह है कि भविष्य का अनुचर अगर (? FooIsEnabled) रिटर्न को याद रखता है; हर फंक्शन की शुरुआत में और अब उन्हें हर फंक्शन की शुरुआत में नए कोड {... को बचाने के लिए याद रखने की जरूरत है। यह कैसे मदद करता है?
bhspencer

मुझे लगता है कि आप विश्लेषण और पृष्ठभूमि संदर्भ damix911 पसंद करते हैं ... मैं संकलन समय (निजी स्थिर सदस्यों का उपयोग करके) में नए कोड उदाहरणों का निर्माण करूंगा, यह मानते हुए कि कोड समय के साथ नहीं बदलेगा और तर्क को शर्त के रूप में पारित करने के लिए परिवर्तन को "निष्पादित" करेगा। (प्रेडिकेट क्लास की तरह) और कोड। लेकिन वह अधिक व्यक्तिगत फीलिंग और स्वाद है।
विक्टर

1
@bhspencer यह जावा में अनाड़ी दिखता है, और ज्यादातर मामलों में यह रणनीति वास्तव में अन्यथा सरल कोड का अतिरेक है। इस तरह के पैटर्न से कई कार्यक्रम लाभ नहीं उठा सकते हैं। हालांकि एक अच्छी बात यह है कि हमने एक नया प्रतीक बनाया है protectजो पुन: उपयोग और दस्तावेज़ के लिए आसान है। यदि आप भविष्य के रखरखाव को बताते हैं कि महत्वपूर्ण कोड के साथ संरक्षित किया जाना चाहिए protect, तो आप पहले से ही उसे बता रहे हैं कि क्या करना है। यदि सुरक्षा नियम बदलते हैं, तो नया कोड अभी भी संरक्षित है। यह फ़ंक्शंस को परिभाषित करने के पीछे बिल्कुल तर्क है, लेकिन ओपी को "वापस" करने की ज़रूरत है returnजो कार्य नहीं कर सकता है।
डेमिक्स 911

11

मैं विचार करना चाहूंगा। यह पैटर्न भारी रूप से DRY पैटर्न को तोड़ रहा है (अपने आप को दोहराएं नहीं)। मेरा मानना ​​है कि यह इस वर्ग की जिम्मेदारी को तोड़ता है। लेकिन यह आपके कोड के नियंत्रण पर निर्भर करता है। आपका प्रश्न बहुत खुला है - आप Fooउदाहरण के लिए कहां बुला रहे हैं ?

मुझे लगता है कि आपके पास कोड जैसा है

foo.bar(); // does nothing if !fooEnabled
foo.baz(); // does also nothing
foo.bat(); // also

शायद आपको इसे कुछ इस तरह कहना चाहिए:

if (fooEnabled) {
   foo.bat();
   foo.baz();
   ...
}

और इसे साफ रखें। उदाहरण के लिए, लॉगिंग:

this.logger.debug(createResourceExpensiveDump())

एक logger खुद से पूछ नहीं है , अगर डिबग सक्षम है। यह सिर्फ लॉग करता है।

इसके बजाय, कॉलिंग क्लास को यह जाँचने की आवश्यकता है:

if (this.logger.isDebugEnabled()) {
   this.logger.debug(createResourceExpensiveDump())
}

यदि यह एक पुस्तकालय है और आप इस वर्ग की कॉलिंग को नियंत्रित नहीं कर सकते IllegalStateExceptionहैं, तो यह बताएं कि यह कॉल अवैध क्यों है और परेशानी का कारण है।


6
यह निश्चित रूप से सरल और आंखों पर आसान है। लेकिन अगर ओपी का लक्ष्य यह सुनिश्चित करना है कि, जैसा कि नए तरीके जोड़े जाते हैं, कि सक्षम तर्क को कभी भी नजरअंदाज नहीं किया जाता है, तो यह रिफैक्टिंग इसे लागू करने के लिए आसान नहीं बनाता है।
sstan

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

4
यह प्रतिरूपकता को तोड़ता है, क्योंकि अब कॉलर को फू के आंतरिक मामलों के बारे में कुछ जानना है (इस मामले में कि क्या यह fooEnabled है)। यह एक उत्कृष्ट उदाहरण है जहां सर्वोत्तम अभ्यास नियमों का पालन करने से समस्या हल नहीं होगी क्योंकि नियम संघर्ष हैं। (मैं अभी भी उम्मीद कर रहा हूं कि कोई व्यक्ति "मैं ऐसा क्यों नहीं सोचा था?" का जवाब देगा।)
इयान गोल्डबी

2
खैर, यह संदर्भ पर बहुत निर्भर करता है कि क्या यह समझ में आता है।
इयान गोल्डबी

3
लॉगिंग बिल्कुल उदाहरण है, जहां मैं अपने कोड में कोई पुनरावृत्ति नहीं चाहता हूं। मैं सिर्फ LOG.debug ("....") लिखना चाहता हूं; - और लकड़हारे को जांचना चाहिए कि क्या मैं वास्तव में डिबग करना चाहता हूं। - एक और उदाहरण क्लोज / क्लिनअप है। - यदि मैं AutoClosable का उपयोग करता हूं तो मुझे अपवाद नहीं चाहिए अगर यह पहले से ही बंद है, तो इसे कुछ नहीं करना चाहिए।
फाल्को

6

IMHO इस के लिए सबसे सुंदर और सबसे अच्छा प्रदर्शन समाधान फू बनाने के लिए एक से अधिक कार्यान्वयन है, साथ में एक बनाने के लिए एक कारखाना विधि:

class Foo {
  protected Foo() {
    // Prevent direct instantiation
  }

  public void bar() {
    // Do something
  }

  public static void getFoo() {
    return fooEnabled ? new Foo() : new NopFoo();
  }
}

class NopFoo extends Foo {
  public void bar() {
    // Do nothing
  }
}

या एक भिन्नता:

class Foo {
  protected Foo() {
    // Prevent direct instantiation
  }

  public void bar() {
    // Do something
  }

  public static void getFoo() {
    return fooEnabled ? new Foo() : NOP_FOO;
  }

  private static Foo NOP_FOO = new Foo() {
    public void bar() {
      // Do nothing
    }
  };
}

जैसा कि सिस्टर बताते हैं, एक इंटरफ़ेस का उपयोग करना बेहतर होगा:

public interface Foo {
  void bar();

  static Foo getFoo() {
    return fooEnabled ? new FooImpl() : new NopFoo();
  }
}

class FooImpl implements Foo {
  FooImpl() {
    // Prevent direct instantiation
  }

  public void bar() {
    // Do something
  }
}

class NopFoo implements Foo {
  NopFoo() {
    // Prevent direct instantiation
  }

  public void bar() {
    // Do nothing
  }
}

अपनी बाकी परिस्थितियों के लिए इसे अपनाएं (क्या आप हर बार एक नया फू बना रहे हैं या उसी उदाहरण का पुन: उपयोग कर रहे हैं, आदि)


1
यह कोनराड के उत्तर के समान नहीं है। मुझे यह पसंद है, लेकिन मुझे लगता है कि यह सुरक्षित होगा अगर, वर्ग की विरासत का उपयोग करने के बजाय, आपने एक इंटरफ़ेस का उपयोग किया, जैसा कि अन्य ने अपने उत्तर में सुझाया है। कारण सरल है: किसी डेवलपर के लिए एक विधि जोड़ना बहुत आसान है Foo, और विस्तारित कक्षा में विधि के नो-ऑप संस्करण को जोड़ना भूल जाता है, इस प्रकार वांछित व्यवहार को दरकिनार कर देता है।
sstan

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

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

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

@PepijnSchmitz - बेशक, स्थिर fooIsEnabled हो सकता है। लेकिन हमें कुछ भी नहीं बताता है कि यह स्थिर है। इसलिए मैं सामान्य मामले पर विचार करता हूं।
निकोलस बारबुल्सको

5

मेरे पास एक और तरीका है: a

interface Foo {
  public void bar();
  public void baz();
  public void bat();
}

class FooImpl implements Foo {
  public void bar() {
    //...
  }
  public void baz() {
    //...
  }
  public void bat() {
    //...
  }
}

class NullFoo implements Foo {
  static NullFoo DEFAULT = new NullFoo();
  public void bar() {}
  public void baz() {}
  public void bat() {}
}

}

और फिर आप कर सकते हैं

(isFooEnabled ? foo : NullFoo.DEFAULT).bar();

शायद आप isFooEnabledएक Fooचर के साथ भी बदल सकते हैं जो या तो FooImplइस्तेमाल किया जा सकता है या NullFoo.DEFAULT। फिर कॉल फिर से सरल है:

Foo toBeUsed = isFooEnabled ? foo : NullFoo.DEFAULT;
toBeUsed.bar();
toBeUsed.baz();
toBeUsed.bat();

BTW, इसे "नल पैटर्न" कहा जाता है।


ओवरआल दृष्टिकोण अच्छा है, लेकिन अभिव्यक्ति का उपयोग करना (isFooEnabled ? foo : NullFoo.DEFAULT).bar();थोड़ा अनाड़ी लगता है। एक तीसरा कार्यान्वयन है जो मौजूदा कार्यान्वयन में से एक को दर्शाता है। एक क्षेत्र के मूल्य को बदलने के बजाय isFooEnabledप्रतिनिधिमंडल के लक्ष्य को बदला जा सकता है। यह कोड की शाखाओं की संख्या कम कर देता है
SpaceTrucker

1
लेकिन आप Fooकॉलिंग कोड में वर्ग के आंतरिक खाना पकाने को निर्वासित कर रहे हैं ! हम कैसे जान सकते हैं कि नहीं isFooEnabled? यह कक्षा में एक आंतरिक क्षेत्र है Foo
निकोलस बारबुलेसको

3

@ कॉलिन के उत्तर के समान कार्यात्मक दृष्टिकोण में, जावा 8 के लैम्ब्डा कार्यों के साथ , सशर्त सुविधा को गार्ड विधि में सक्षम / अक्षम कोड को टॉगल करना संभव है ( executeIfEnabled) जो एक्शन लैम्ब्डा को स्वीकार करता है, जिसे कोड को सशर्त निष्पादित किया जा सकता है। बीतने के।

यद्यपि आपके मामले में, यह दृष्टिकोण कोड की किसी भी पंक्ति को सहेज नहीं पाएगा, लेकिन इसे ऊपर उठाकर, अब आपके पास अन्य फ़ीचर टॉगल चिंताओं, प्लस AOP या डीबगिंग चिंताओं जैसे लॉगिंग, डायग्नोस्टिक्स, प्रोफाइलिंग एट अल को केंद्रीकृत करने का विकल्प है।

यहां लंबोदा का उपयोग करने का एक लाभ यह है कि executeIfEnabledविधि को ओवरलोड करने की आवश्यकता से बचने के लिए क्लोजर का उपयोग किया जा सकता है ।

उदाहरण के लिए:

class Foo {
    private Boolean _fooIsEnabled;

    public Foo(Boolean isEnabled) {
        _fooIsEnabled = isEnabled;
    }

    private void executeIfEnabled(java.util.function.Consumer someAction) {
        // Conditional toggle short circuit
        if (!_fooIsEnabled) return;

        // Invoke action
        someAction.accept(null);
    }

    // Wrap the conditionally executed code in a lambda
    public void bar() {
        executeIfEnabled((x) -> {
            System.out.println("Bar invoked");
        });
    }

    // Demo with closure arguments and locals
    public void baz(int y) {
        executeIfEnabled((x) -> {
            System.out.printf("Baz invoked %d \n", y);
        });
    }

    public void bat() {
        int z = 5;
        executeIfEnabled((x) -> {
            System.out.printf("Bat invoked %d \n", z);
        });
    }

एक परीक्षण के साथ:

public static void main(String args[]){
    Foo enabledFoo = new Foo(true);
    enabledFoo.bar();
    enabledFoo.baz(33);
    enabledFoo.bat();

    Foo disabledFoo = new Foo(false);
    disabledFoo.bar();
    disabledFoo.baz(66);
    disabledFoo.bat();
}

इसके अलावा दामिक्स के दृष्टिकोण के समान, बिना विधि के ओवरराइड के साथ एक इंटरफ़ेस और अनाम वर्ग कार्यान्वयन की आवश्यकता के बिना।
स्टुअर्टएलसी

2

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

class Foo {

  public static void main(String[] args) {
      Foo foo = new Foo();
      foo.fooIsEnabled = false;
      foo.execute("bar");
      foo.fooIsEnabled = true;
      foo.execute("baz");
  }

  boolean fooIsEnabled;

  public void execute(String method) {
    if(!fooIsEnabled) {return;}
    try {
       this.getClass().getDeclaredMethod(method, (Class<?>[])null).invoke(this, (Object[])null);
    }
    catch(Exception e) {
       // best to handle each exception type separately
       e.printStackTrace();
    }
  }

  // Changed methods to private to reinforce usage of execute method
  private void bar() {
    System.out.println("bar called");
    // bar stuff here...
  }
  private void baz() {
    System.out.println("baz called");
    // baz stuff here...
  }
  private void bat() {
    System.out.println("bat called");
    // bat stuff here...
  }
}

प्रतिबिंब से निपटने के लिए थोड़ा अजीब है, अगर वहाँ पहले से ही वर्गों है कि आप के लिए ऐसा करते हैं, पहले से ही उल्लेख किया है Proxy
स्पेसट्रैक

आप कैसे कर सकते हैं foo.fooIsEnabled ...? एक प्राथमिकता, यह वस्तु का आंतरिक क्षेत्र है, हम इसे बाहर नहीं देख सकते हैं और नहीं करना चाहते हैं।
निकोलस बारबुल्सको

2

यदि केवल जावा कार्यात्मक होने पर थोड़ा बेहतर था। यह लगता है कि सबसे OOO समाधान वर्ग बनाना है जो किसी एकल फ़ंक्शन को लपेटता है इसलिए इसे केवल तभी कहा जाता है जब foo सक्षम हो।

abstract class FunctionWrapper {
    Foo owner;

    public FunctionWrapper(Foo f){
        this.owner = f;
    }

    public final void call(){
        if (!owner.isEnabled()){
            return;
        }
        innerCall();
    }

    protected abstract void innerCall();
}

और फिर लागू करें bar, bazऔर batअनाम वर्गों के रूप में जो विस्तार करते हैं FunctionWrapper

class Foo {
    public boolean fooIsEnabled;

    public boolean isEnabled(){
        return fooIsEnabled;
    }

    public final FunctionWrapper bar = new FunctionWrapper(this){
        @Override
        protected void innerCall() {
            // do whatever
        }
    };

    public final FunctionWrapper baz = new FunctionWrapper(this){
        @Override
        protected void innerCall() {
            // do whatever
        }
    };

    // you can pass in parms like so 
    public final FunctionWrapper bat = new FunctionWrapper(this){
        // some parms:
        int x,y;
        // a way to set them
        public void setParms(int x,int y){
            this.x=x;
            this.y=y;
        }

        @Override
        protected void innerCall() {
            // do whatever using x and y
        }
    };
}

एक अन्य विचार

ग्लोगल के अशक्त समाधान का उपयोग करें, लेकिन निम्न वर्ग के (निजी निर्माणकर्ताओं के साथ) FooImplऔर NullFooआंतरिक वर्ग बनाएं :

class FooGateKeeper {

    public boolean enabled;

    private Foo myFooImpl;
    private Foo myNullFoo;

    public FooGateKeeper(){
        myFooImpl= new FooImpl();
        myNullFoo= new NullFoo();
    }

    public Foo getFoo(){
        if (enabled){
            return myFooImpl;
        }
        return myNullFoo;
    }  
}

इस तरह आपको उपयोग करने के लिए याद रखने की चिंता करने की आवश्यकता नहीं है (isFooEnabled ? foo : NullFoo.DEFAULT)


कहते हैं कि आपके पास: Foo foo = new Foo()कॉल करने के लिए barआप लिखेंगेfoo.bar.call()
कॉलिन

1

ऐसा लगता है कि जब फू को सक्षम नहीं किया जाता है तो क्लास कुछ भी नहीं करती है इसलिए इसे उच्च स्तर पर व्यक्त नहीं करें जहां आप फू उदाहरण बनाते हैं या प्राप्त करते हैं?

class FooFactory
{
 static public Foo getFoo()
 {
   return isFooEnabled ? new Foo() : null;
 }
}
 ...
 Foo foo = FooFactory.getFoo();
 if(foo!=null)
 {
   foo.bar();
   ....
 }     

यह केवल तभी काम करता है यदि FooEnabled एक स्थिर है। एक सामान्य मामले में, आप अपना एनोटेशन बना सकते हैं।


कोनराड, क्या आप एनोटेशन पर विकसित कर सकते हैं?
निकोलस बारबुलेसको

मूल कोड निर्धारित करता है कि क्या fooIsEnabledएक विधि कहा जाता है। आप इसे इंस्टेंटेशन से पहले करते हैं Foo। जल्दबाज़ी है। इस बीच मान बदल सकता है।
निकोलस बारबुलेसको

मुझे लगता है कि आप एक बिंदु याद करते हैं। एक प्राथमिकता, वस्तुओं isFooEnabledका एक उदाहरण क्षेत्र है Foo
निकोलस बारबुल्स्को

1

मैं जावा सिंटैक्स से परिचित नहीं हूं। अनुमान है कि जावा में, बहुरूपता, स्थिर संपत्ति, अमूर्त वर्ग और विधि है:

    public static void main(String[] args) {
    Foo.fooIsEnabled = true; // static property, not particular to a specific instance  

    Foo foo = new bar();
    foo.mainMethod();

    foo = new baz();
    foo.mainMethod();

    foo = new bat();
    foo.mainMethod();
}

    public abstract class Foo{
      static boolean fooIsEnabled;

      public void mainMethod()
      {
          if(!fooIsEnabled)
              return;

          baMethod();
      }     
      protected abstract void baMethod();
    }
    public class bar extends Foo {
        protected override baMethod()
        {
            // bar implementation
        }
    }
    public class bat extends Foo {
        protected override baMethod()
        {
            // bat implementation
        }
    }
    public class baz extends Foo {
        protected override baMethod()
        {
            // baz implementation
        }
    }

कौन कहता है कि किया जा रहा सक्षम है स्थिर वर्ग की संपत्ति?
निकोलस बारबुल्स्को जू

क्या new bar()मतलब है?
निकोलस बारबुल्सको

जावा में, हम Nameबड़े अक्षर के साथ एक वर्ग लिखते हैं ।
निकोलस बारबुलेसको

इसके लिए कॉलिंग कोड का तरीका बदलना बहुत जरूरी है। हम एक विधि को सामान्य रूप से कहते हैं bar():। यदि आपको उसे बदलने की आवश्यकता है, तो आप बर्बाद हैं।
निकोलस बारबुल्सको

1

मूल रूप से आपके पास एक ध्वज है जो यदि सेट है, तो फ़ंक्शन कॉल को छोड़ दिया जाना चाहिए। इसलिए मुझे लगता है कि मेरा समाधान मूर्खतापूर्ण होगा, लेकिन यहां यह है।

Foo foo = new Foo();

if (foo.isEnabled())
{
    foo.doSomething();
}

यदि आप किसी फ़ंक्शन को निष्पादित करने से पहले कुछ कोड निष्पादित करना चाहते हैं, तो यहां एक सरल प्रॉक्सी का कार्यान्वयन है।

class Proxy<T>
{
    private T obj;
    private Method<T> proxy;

    Proxy(Method<T> proxy)
    {
        this.ojb = new T();
        this.proxy = proxy;
    }

    Proxy(T obj, Method<T> proxy)
    {
        this.obj = obj;
        this.proxy = proxy;
    }

    public T object ()
    {
        this.proxy(this.obj);
        return this.obj;
    }
}

class Test
{
    public static void func (Foo foo)
    {
        // ..
    }

    public static void main (String [] args)
    {
        Proxy<Foo> p = new Proxy(Test.func);

        // how to use
        p.object().doSomething();
    }
}

class Foo
{
    public void doSomething ()
    {
        // ..
    }
}

कोड के अपने पहले ब्लॉक के लिए, आपको एक दृश्य विधि की आवश्यकता है isEnabled()। एक प्राथमिकता, सक्षम किया जा रहा है की आंतरिक खाना पकाने Foo, उजागर नहीं है।
निकोलस बारबुल्सको

कॉलिंग कोड नहीं कर सकता है और नहीं चाहता है , पता है कि क्या वस्तु सक्षम है
निकोलस बारबुल्सको

0

एक और उपाय है, प्रतिनिधि (कार्य करने के लिए सूचक) का उपयोग करके। आपके पास एक अनूठी विधि हो सकती है जो पहले सत्यापन कर रही है और फिर फ़ंक्शन (पैरामीटर) के अनुसार संबंधित विधि को कॉल किया जा सकता है। C # कोड:

internal delegate void InvokeBaxxxDelegate();

class Test
{
    private bool fooIsEnabled;

    public Test(bool fooIsEnabled)
    {
        this.fooIsEnabled = fooIsEnabled;
    }

    public void Bar()
    {
        InvokeBaxxx(InvokeBar);
    }

    public void Baz()
    {
        InvokeBaxxx(InvokeBaz);
    }

    public void Bat()
    {
        InvokeBaxxx(InvokeBat);
    }

    private void InvokeBaxxx(InvokeBaxxxDelegate invoker)
    {
        if (!fooIsEnabled) return;
        invoker();
    }

    private void InvokeBar()
    {
        // do Invoke bar stuff
        Console.WriteLine("I am Bar");
    }

    private void InvokeBaz()
    {
        // do Invoke bar stuff
        Console.WriteLine("I am Baz");
    }

    private void InvokeBat()
    {
        // do Invoke bar stuff
        Console.WriteLine("I am Bat");
    }
}

2
सही है, यह जावा को चिह्नित किया गया है और यही कारण है कि मैं जोर देता हूं और "कोड इन सी #" लिखा है क्योंकि मुझे जावा नहीं पता है। चूंकि यह एक डिज़ाइन पैटर्न प्रश्न है, इसलिए भाषा महत्वपूर्ण नहीं है।
एह

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