কোনও ক্লাসের প্রতিটি পদ্ধতি কোডের একটি নির্দিষ্ট ব্লক দিয়ে শুরু করার জন্য কি কোনও দুর্দান্ত উপায় আছে?


143

আমার একটি ক্লাস রয়েছে যেখানে প্রতিটি পদ্ধতি একইভাবে শুরু হয়:

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

fooIsEnabledক্লাসের প্রতিটি পাবলিক পদ্ধতির অংশটি প্রয়োজন (এবং আশাকরি প্রতিবার লিখবেন না) এর একটি দুর্দান্ত উপায় আছে ?


45
অ্যাস্পেক্ট ওরিয়েন্টেড প্রোগ্রামিংয়ে দেখুন (বিশেষত পরামর্শের আগে )।
সোটিরিওস ডেলিমনলিস

15
আপনার এই বয়লারপ্লেটটি কতটি পদ্ধতির জন্য ব্যবহার করতে হবে? আপনি এওপি প্রবর্তনের পথে নামার আগে আপনি কেবলমাত্র এই সামান্য কিছুটা পুনরাবৃত্তি কোডটি বিবেচনা করতে চাইতে পারেন। কখনও কখনও অল্প কপি এবং পেস্ট করা সহজ সমাধান।
bhspencer

51
আমি সন্দেহ করি যে আপনার ভবিষ্যতের রক্ষণাবেক্ষণকারী এওপি কাঠামোটি শিখার চেয়ে অতিরিক্ত বয়লার প্লেটের সাথে আরও সুখী হবে।
bhspencer

7
যদি ক্লাসের প্রতিটি পদ্ধতিতে তাদের কোডের প্রথম লাইনে একই জিনিস করতে হয় তবে আমাদের একটি খারাপ নকশা রয়েছে।
তুলিনাস কর্ডোভা

7
@ ব্যবহারকারী 1598390: প্রশ্নটি এখানে বিষয়বস্তু নয়, এবং প্রোগ্রামারদের সুযোগ সম্পর্কে এমন কিছুই নেই যা প্রশ্নটি বিশেষত অর্থবহ করে তোলে।
রবার্ট হার্ভে

উত্তর:


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চেকটি বাড়ানোর প্রয়োজন হয় তবে নিরাপদে এবং এক জায়গায় এটি করা খুব সহজ।
  • এটি একধরনের সুন্দর যে আপনি অন্তর্নির্মিত জাভা কার্যকারিতা সহ এই এওপি-জাতীয় আচরণ পেতে পারেন। আপনি যেমন কিছু অন্যান্য কাঠামো একীকরণ করতে বাধ্য করা হয় না Spring, যদিও তারা অবশ্যই ভাল বিকল্প হতে পারে।

পরিষ্কার কথা বলতে গেলে কিছুটা ডাউনসাইড হ'ল:

  • প্রক্সি আমন্ত্রণগুলি পরিচালনা করে এমন কিছু বাস্তবায়ন কোড কুৎসিত। কেউ কেউ আরও বলবেন যে শ্রেণীর তাত্ক্ষণিকতা রোধ করার জন্য অভ্যন্তরীণ ক্লাসগুলি করা FooImplকুশ্রী।
  • আপনি যদি একটি নতুন পদ্ধতি যুক্ত করতে চান তবে Fooআপনাকে 2 স্পটে পরিবর্তন করতে হবে: বাস্তবায়ন শ্রেণি এবং ইন্টারফেস। বড় কথা নয়, তবে এটি এখনও কিছুটা বেশি কাজ।
  • প্রক্সি অনুরোধগুলি নিখরচায় নয়। ওভারহেডের একটি নির্দিষ্ট পারফরম্যান্স রয়েছে। যদিও সাধারণ ব্যবহারের জন্য, এটি লক্ষণীয় হবে না। আরও তথ্যের জন্য এখানে দেখুন ।

সম্পাদনা করুন:

ফ্যাবিয়ান স্ট্রিটেলের মন্তব্য আমার উপরের সমাধানটির সাথে 2 টি বিরক্তি নিয়ে ভাবছে যা আমি স্বীকার করব, আমি নিজের সম্পর্কে খুশি নই:

  1. অনুরোধ হ্যান্ডলার "getEn सक्षम" এবং "সেট-সক্ষম" পদ্ধতিতে "সক্ষম-চেক" এড়ানোর জন্য যাদু স্ট্রিংগুলি ব্যবহার করে। যদি পদ্ধতির নামগুলি সংশোধন করা হয় তবে এটি সহজেই ভেঙে যেতে পারে।
  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
আমি পেয়েছি যে এটি একটি চতুর সমাধান তবে আপনি কি সত্যিই এটি ব্যবহার করবেন?
bhspencer

1
খুব সুন্দর কাজ, আপনি প্রতিটি পদ্ধতির শুরুতে পাওয়া এই সাধারণ আচরণ দিয়ে অবজেক্টটি সাজানোর জন্য ডায়নামিক প্রক্সি প্যাটার্নটি ব্যবহার করছেন।
ভিক্টর

11
@ বিএসপি স্পেন্সার: খুব বৈধ প্রশ্ন question আমি ব্যতিক্রম হ্যান্ডলিং, লগিং, লেনদেন পরিচালন ইত্যাদির জন্য এটি বহুবার ব্যবহার করেছি I'll তবে আমি যদি আশা করি যে ক্লাসটি জটিলতায় অনেক বৃদ্ধি পাবে এবং আমি যেমন করি তেমন সমস্ত পদ্ধতিতে সামঞ্জস্যপূর্ণ আচরণ নিশ্চিত করতে চাই, আমি এই সমাধানটিকে আপত্তি করি না।
সস্তান

1
এখানে 97% অশুভের অংশ হতে হবে না, তবে এই প্রক্সি শ্রেণীর পারফরম্যান্সের কী কী প্রভাব রয়েছে?
কর্সিকা

5
@ করসিকা: ভাল প্রশ্ন। কোনও সন্দেহ নেই যে ডায়নামিক প্রক্সিগুলি সরাসরি পদ্ধতি পদ্ধতি কলগুলির চেয়ে ধীর হয়। যদিও সাধারণ ব্যবহারের জন্য, কর্মক্ষমতা ওভারহেড দুর্ভেদ্য হতে হবে। আপনার আগ্রহী থাকলে সম্পর্কিত এস থ্রেড: জাভা ডায়নামিক প্রক্সিটির পারফরম্যান্স ব্যয়
৫১-এ

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 এর ভিতরে আপনি ধরে নিচ্ছেন যে এই অবজেক্টের ক্লায়েন্ট সত্যে বোকা বানিয়েছে, তাই চেকিংয়ের দরকার নেই। একই ফুডিজডিবাহাভিওর ক্লাসে যায়। আবার চেক করুন, এতে কোড দিন।
ভিক্টর

2
ধন্যবাদ @ বায়উ.ইও, আসুন অপের উত্তর না আসা পর্যন্ত অপেক্ষা করুন। আমি মনে করি যে সম্প্রদায়টি এখানে একটি কাজের নরক করছে, এখানে প্রায় অনেক ভাল টিপস রয়েছে!
ভিক্টর

2
@ ডায়াজডিজের সাথে একমত, আমি একেবারে তুচ্ছ শ্রেণির ব্যতীত অন্য কোনও কিছুর জন্য এটি বাস্তবায়নের কল্পনা করতে পারি না। এটা ঠিক খুব সমস্যাযুক্ত এর বিবেচনায় যে bar()মধ্যে FooEnabledBehaviorএবং bar()মধ্যে FooDisabledBehaviorদুই মধ্যে সম্ভবত এমনকি একটি একক লাইন বিভিন্ন সঙ্গে, একই কোড অনেক ভাগ পারে। আপনি খুব সহজেই সক্ষম হতে পারেন, বিশেষত যদি এই কোডটি জুনিয়র ডেভস (যেমন আমার মতো) দ্বারা বজায় রাখা হয়, তবে অচিন্তনীয় এবং অকেজো করার মতো ক্রেপের একটি বিশাল জগাখিচুড়ি দিয়ে শেষ হয়। যে কোনও কোডের সাথে এটি ঘটতে পারে তবে এটি সত্যিই দ্রুত স্ক্রু করা খুব সহজ বলে মনে হয়। যদিও +1, কারণ ভাল পরামর্শ।
ক্রিস সাইরেফাইস

1
মমমম ... আমি ছেলেরা না .. তবে প্রথমে মন্তব্যের জন্য ধন্যবাদ। আমার পক্ষে কোডের আকার যতক্ষণ না এটি "পরিষ্কার" এবং "পঠনযোগ্য" হিসাবে সমস্যা হয় না। আমার পক্ষে আমার যুক্তি দেওয়া উচিত যে আমি কোনও বাহ্যিক শ্রেণি ব্যবহার করছি না .. যা বিষয়গুলিকে আরও অ্যাক্সেসযোগ্য করে তুলবে। এবং যদি কিছু সাধারণ আচরণ থাকে তবে আসুন এটি একটি কমন বিহ্যাভিওর ক্লাসে সজ্জিত করুন এবং যেখানে এটি প্রয়োজন সেখানে প্রতিনিধি দিন। জিওএফ বইয়ে (শেখার জন্য আমার প্রিয় বই নয়, তবে ভাল রেসিপি রয়েছে) আপনি এই উদাহরণটি পেয়েছেন: en.wikedia.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 জাভাটির একটি এওপি এক্সটেনশন এবং আপনি কিছুটা আকাঙ্ক্ষা পেতে এটি দেখতে পারেন।

আমি যতদূর জানি জাভাতে এওপি-র জন্য সরাসরি সমর্থন নেই। কিছু জিওএফ নিদর্শন রয়েছে যা এর সাথে সম্পর্কিত, যেমন টেম্পলেট পদ্ধতি এবং কৌশল তবে এটি আপনাকে কোডের লাইনগুলি সংরক্ষণ করবে না really

জাভা এবং বেশিরভাগ অন্যান্য ভাষায় আপনি ক্রিয়াকলাপগুলিতে আপনার প্রয়োজনীয় পুনরাবৃত্তি যুক্তি সংজ্ঞায়িত করতে পারেন এবং তথাকথিত শৃঙ্খলাবদ্ধ কোডিং পদ্ধতির অবলম্বন করতে পারেন যেখানে আপনি তাদেরকে সঠিক সময়ে ডেকেছেন।

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

তবে এটি আপনার ক্ষেত্রে খাপ খায় না কারণ আপনি চাইবেন যে যুক্তিযুক্ত কোডটি থেকে ফিরে আসতে সক্ষম হয় checkBalance। যে ভাষাগুলিতে ম্যাক্রো সমর্থন করে (যেমন সি / সি ++) আপনি সংজ্ঞা দিতে পারেন checkSomePreconditionএবং checkSomePostconditionম্যাক্রো হিসাবে এবং সেগুলি সংকলকটি আহ্বানের আগে কেবল প্রিপ্রসেসর দ্বারা প্রতিস্থাপন করা হবে:

#define checkSomePrecondition \
    if (!fooIsEnabled) return;

জাভা বাক্সের বাইরে নেই। এটি কাউকে আপত্তি করতে পারে তবে অতীতে পুনরাবৃত্ত কোডিংয়ের কাজগুলিকে স্বয়ংক্রিয় করতে আমি স্বয়ংক্রিয় কোড জেনারেশন এবং টেম্পলেট ইঞ্জিন ব্যবহার করেছি। আপনি যদি আপনার জাভা ফাইলগুলিকে উপযুক্ত প্রিপ্রোসেসর দিয়ে সংকলন করার আগে প্রক্রিয়া করেন, উদাহরণস্বরূপ জিনজা 2, আপনি সি তে যা কিছু সম্ভব তার অনুরূপ কিছু করতে পারেন

সম্ভাব্য খাঁটি জাভা পদ্ধতির

আপনি যদি খাঁটি জাভা সমাধান খুঁজছেন তবে আপনি যা খুঁজে পেতে পারেন তা সম্ভবত সংক্ষিপ্ত হবে না। তবে এটি এখনও আপনার প্রোগ্রামের সাধারণ অংশগুলি নির্ধারণ করতে পারে এবং কোড সদৃশতা এবং বাগগুলি এড়াতে পারে। আপনি এর মতো কিছু করতে পারেন (এটি কৌশল- চালিত প্যাটার্নের এক ধরণের )। মনে রাখবেন যে সি # এবং জাভা 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
এটি কি রাস্তায় ক্যানটিকে লাথি দেয় না। যা ভবিষ্যতের রক্ষণাবেক্ষণকারীকে ((fooIsEn सक्षम) ফিরে আসার কথা মনে রাখে; প্রতিটি ক্রিয়াকলাপের শুরুতে এবং এখন তাদের রক্ষা করতে হবে (নতুন কোড every ... প্রতিটি ক্রিয়াকলাপের শুরুতে। এটি কীভাবে সহায়তা করে?
bhspencer

আমি আপনাকে বিশ্লেষণ এবং পটভূমি প্রসঙ্গে ড্যামিক্স ৯১১ পছন্দ করি ... সংকলনের সময় আমি নতুন কোড দৃষ্টান্ত তৈরি করব (ব্যক্তিগত স্ট্যাটিক সদস্য ব্যবহার করে) ধরে নিচ্ছি যে কোড সময়ের সাথে পরিবর্তিত হবে না এবং "এক্সিকিউটিআইফ" এ পরিবর্তনের নাম পরিবর্তন করে একটি শর্ত হিসাবে পাস করবে (প্রেডিকেট ক্লাসের মতো) এবং কোড। তবে এটি ব্যক্তিগত পতন এবং স্বাদ বেশি।
ভিক্টর

1
@bhspencer এটি জাভাতে বরং আনাড়ি বলে মনে হচ্ছে এবং বেশিরভাগ ক্ষেত্রে এই কৌশলটি অন্যথায় সহজ কোডের সত্যিকার অর্থেই একটি অত্যুৎসাহী। অনেকগুলি প্রোগ্রাম যেমন একটি প্যাটার্ন থেকে উপকার করতে পারে না। তবে একটি দুর্দান্ত জিনিস হ'ল আমরা একটি নতুন প্রতীক তৈরি করেছি protectযা পুনরায় ব্যবহার এবং ডকুমেন্টটি সহজ। যদি আপনি ভবিষ্যতের রক্ষণাবেক্ষণকারীকে বলেন যে সমালোচনামূলক কোডটি সুরক্ষিত করা উচিত protect, আপনি ইতিমধ্যে তাকে কী করতে হবে তা বলছেন। সুরক্ষা বিধি পরিবর্তন হলে, নতুন কোডটি এখনও সুরক্ষিত থাকবে। এটি হ'ল ফাংশন সংজ্ঞায়নের পিছনে যুক্তি কিন্তু ওপিকে "একটি return" ফিরিয়ে দেওয়ার দরকার ছিল যা ফাংশনগুলি করতে পারে না।
Damix911

11

আমি রিফ্যাক্টরিং বিবেচনা করব। এই প্যাটার্নটি ডিআরওয়াই প্যাটার্নটি ভারিভাবে ভঙ্গ করছে (নিজেকে পুনরাবৃত্তি করবেন না)। আমি বিশ্বাস করি এটি এই শ্রেণীর দায়িত্ব ভঙ্গ করে। তবে এটি আপনার কোডের নিয়ন্ত্রণের উপর নির্ভর করে। আপনার প্রশ্নটি খুব উন্মুক্ত - আপনি 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, তবে এই কলটি অবৈধ এবং সমস্যা সৃষ্টি করার কারণ কেন তা ব্যাখ্যা করে throw


6
এটি অবশ্যই সহজ এবং সহজ চোখের উপর। তবে ওপি'র লক্ষ্য যদি নিশ্চিত হয় যে নতুন পদ্ধতি যুক্ত হওয়ার সাথে সাথে, সক্ষম যুক্তিটিকে কখনই বাইপাস করা যায় না, তবে এই রিফ্যাক্টরিং এটি কার্যকর করা সহজ করে না।
সানস্ট

4
এছাড়াও আপনার লগ উদাহরণের জন্য, আমি বলব এতে আরও অনেক পুনরাবৃত্তি জড়িত - প্রতিবার আপনি লগ করতে চাইলে আপনাকে লগার সক্ষম হয়েছে কিনা তা পরীক্ষা করে দেখতে হবে। আমি যে কোনও ক্লাসে পদ্ধতির সংখ্যার চেয়ে বেশি লাইন লগ করতে চাই ...
টি কিলি

4
এটি মডিউলারিটি ভেঙে দেয়, কারণ এখন কলকারীকে ফু-র ইন্টার্নাল সম্পর্কে কিছু জানতে হবে (এই ক্ষেত্রে এটি fooEnable কিনা তা)। এটি একটি সর্বোত্তম উদাহরণ যেখানে সর্বোত্তম অনুশীলনের নিয়ম অনুসরণ করা সমস্যার সমাধান করতে পারে না কারণ নিয়মগুলির বিরোধ। (আমি এখনও আশা করছি যে কেউ একটি "কেন আমি এটি ভেবে দেখিনি?" এর উত্তর নিয়ে
আসবে

2
ঠিক আছে, এটি প্রাসঙ্গিকতার উপর নির্ভর করে যে এটি বোধগম্য হয় কিনা।
আয়ান গোল্ডবি

3
লগিং হুবহু উদাহরণ, যেখানে আমি আমার কোডটিতে কোনও পুনরাবৃত্তি চাই না। আমি শুধু LOG.debug ("....") লিখতে চাই; - এবং লগারের চেক করা উচিত আমি সত্যই ডিবাগ করতে চাই কিনা। - আরেকটি উদাহরণ হ'ল ক্লোজিং / ক্লিনআপ। - আমি যদি অটোক্লোজেবল ব্যবহার করি তবে ইতিমধ্যে এটি বন্ধ থাকলে আমি এর ব্যতিক্রম চাই না, এটি কিছু না করা উচিত।
ফ্যালকো

6

আইএমএইচও এর সবচেয়ে মার্জিত এবং সেরা পারফরম্যান্স সমাধান হ'ল ফু এর একাধিক বাস্তবায়ন, একসাথে একটি তৈরির জন্য একটি কারখানার পদ্ধতি:

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
    }
  };
}

যেমনটি আস্তানা দেখায়, ইন্টারফেস ব্যবহার করা আরও ভাল better

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এবং বর্ধিত শ্রেণিতে পদ্ধতির নো-অপশন সংস্করণ যুক্ত করতে ভুলে যান, এভাবে পছন্দসই আচরণকে বাইপাস করে।
সানস্ট

2
@ স্প্যান আপনি ঠিক বলেছেন, এটি আরও ভাল হবে। ক্রেস্টিনার আসল উদাহরণটি যতটা সম্ভব বিঘ্ন এড়ানোর জন্য যতটা সম্ভব সংশোধন করা আমার পক্ষে এটি পছন্দ হয়েছিল তবে এটি প্রাসঙ্গিক। আমি আমার উত্তর আপনার পরামর্শ যোগ করব।
পেপিজন স্মিটজ

1
আমার মনে হয় আপনি একটা বিষয় মিস করেছেন isFooEnabledএর তাত্ক্ষণিক সময়ে আপনি নির্ধারণ করুন Foo। এটা খুব তাড়াতাড়ি। মূল কোডটিতে, কোনও পদ্ধতি চালানো হলে এটি করা হয়। এর isFooEnabledমধ্যে পরিবর্তন হতে পারে।
নিকোলাস বারবুলেসকো

1
@ নিকোলাস বার্বুলেসকো আপনি জানেন না যে, fooIsEnabled একটি ধ্রুবক হতে পারে। অথবা এটি এমনভাবে ব্যবহার করা যেতে পারে যা এটি কার্যকরভাবে ধ্রুবক করে তোলে। অথবা এটি কয়েকটি ভাল সংজ্ঞায়িত স্থানে সেট করা যেতে পারে যাতে প্রতিবারের জন্য ফু এর নতুন উদাহরণ পাওয়া সহজ হয়। অথবা প্রতিবার ফু ব্যবহার করার সময় এটির একটি নতুন উদাহরণ পাওয়া গ্রহণযোগ্য হতে পারে। আপনি জানেন না, এ কারণেই আমি লিখেছিলাম: "আপনার বাকি পরিস্থিতিতে এটি খাপ খাইয়ে নিন"।
পেপিজন স্মিটজ

@ পেপিজনশ্মিটজ - অবশ্যই, ধ্রুবক 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();

বিটিডাব্লু, একে "নাল প্যাটার্ন" বলা হয়।


ওভারাল অ্যাপ্রোচ ভাল, তবে এক্সপ্রেশনটি ব্যবহার করা (isFooEnabled ? foo : NullFoo.DEFAULT).bar();কিছুটা আনাড়ি বলে মনে হচ্ছে। একটি তৃতীয় বাস্তবায়ন রয়েছে যা বিদ্যমান বাস্তবায়নগুলির মধ্যে একটিতে প্রতিনিধিত্ব করে। কোনও ক্ষেত্রের মান পরিবর্তনের পরিবর্তে isFooEnabledপ্রতিনিধিদের লক্ষ্য পরিবর্তন করা যেতে পারে। এটি কোডে শাখার সংখ্যা হ্রাস করে
স্পেসট্রাকার

1
কিন্তু আপনি Fooকলিং কোডে ক্লাসের অভ্যন্তরীণ রান্নাটি নির্বাসন দিচ্ছেন ! আমরা কীভাবে জানতে পারি isFooEnabled? এটি শ্রেণীর অভ্যন্তরীণ ক্ষেত্র Foo
নিকোলাস বারবুলেসো

3

জাভা 8 এর ল্যাম্বদা ফাংশন সহ @ কলিনের উত্তরের অনুরূপ ক্রিয়ামূলক পন্থায়, শর্তসাপেক্ষ বৈশিষ্ট্য টগল সক্ষম / অক্ষম কোডটিকে কোনও প্রহরী পদ্ধতিতে মোড়ানো সম্ভব (executeIfEnabled ) অ্যাকশন ল্যাম্বদা গ্রহণ করে, কোন কোডটি শর্তসাপেক্ষে কার্যকর করা যেতে পারে which পাশ করে।

যদিও আপনার ক্ষেত্রে, এই পদ্ধতিটি কোডের কোনও লাইন সংরক্ষণ করবে না, এটি ডিআরআই করেই, আপনার এখন অন্যান্য বৈশিষ্ট্য টগল উদ্বেগকে কেন্দ্রিয় করার বিকল্প রয়েছে, প্লাস এওপি বা লগিং, ডায়াগনস্টিকস, প্রোফাইলিং ইত্যাদি ইত্যাদি উদ্বেগের মতো উদ্বেগকে central

এখানে ল্যাম্বডাস ব্যবহারের একটি সুবিধা হ'ল 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
        }
    };
}

অন্য আইডিয়া

Glglgl এর nullable দ্রবণটি ব্যবহার করুন তবে নীচের শ্রেণীর মেক 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

দেখে মনে হচ্ছে ক্লাব যখন কিছুই সক্ষম হয় না তখন Foo সক্ষম হয় না তাই আপনি কেন উচ্চতর স্তরে এটি প্রকাশ করবেন না যেখানে আপনি Foo দৃষ্টান্ত তৈরি করেন বা পাবেন?

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

এটি কেবল তখনই কাজ করে যদি isoooooonable যদিও একটি ধ্রুবক হয়। সাধারণ ক্ষেত্রে, আপনি নিজের টীকাটি তৈরি করতে পারেন।


কনরাড, আপনি কি টীকাতে বিকাশ করতে পারবেন?
নিকোলাস বারবুলেসকো

মূল কোডটি নির্ধারণ করে যে 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

প্রতিনিধি (ফাংশনটি পয়েন্টার) ব্যবহার করে আরও একটি সমাধান রয়েছে। আপনার কাছে একটি অনন্য পদ্ধতি থাকতে পারে যা প্রথমে যাচাইকরণ করছে এবং তারপরে ফোন করার ফাংশন (পরামিতি) অনুযায়ী প্রাসঙ্গিক পদ্ধতিতে কল করছে। সি # কোড:

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
ঠিক আছে, এটি জাভা হিসাবে চিহ্নিত হয়েছে এবং আমি জাভা জানি না বলেই আমি "কোড ইন সি #" তে জোর দিয়েছি এবং লিখেছি। যেহেতু এটি একটি নকশা প্যাটার্নের প্রশ্ন তাই ভাষাটি গুরুত্বপূর্ণ নয়।
এহহ

উহু! আমি বুঝতে পেরেছি, এর জন্য দুঃখিত, শুধুমাত্র সাহায্য করার চেষ্টা করেছি এবং একটি সমাধান খুঁজে বের করার চেষ্টা করেছি। আপনাকে ধন্যবাদ
এহ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.