निम्नलिखित कोड स्निपेट से बहुत अधिक / / -अगर बहुत से बचने का बेहतर तरीका क्या है?


14

मैं एक सर्वलेट लिखने की कोशिश कर रहा हूं जो "एक्शन" मूल्य के आधार पर कार्य करता है इसे इनपुट के रूप में पारित किया।

इसका नमूना यहाँ दिया गया है

public class SampleClass extends HttpServlet {
     public static void action1() throws Exception{
          //Do some actions
     }
     public static void action2() throws Exception{
          //Do some actions
     }
     //And goes on till action9


     public void doPost(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException {
          String action = req.getParameter("action");

          /**
           * I find it difficult in the following ways
           * 1. Too lengthy - was not comfortable to read
           * 2. Makes me fear that action1 would run quicker as it was in the top
           * and action9 would run with a bit delay - as it would cross check with all the above if & else if conditions
           */

          if("action1".equals(action)) {
               //do some 10 lines of action
          } else if("action2".equals(action)) {
               //do some action
          } else if("action3".equals(action)) {
               //do some action
          } else if("action4".equals(action)) {
               //do some action
          } else if("action5".equals(action)) {
               //do some action
          } else if("action6".equals(action)) {
               //do some action
          } else if("action7".equals(action)) {
               //do some action
          } else if("action8".equals(action)) {
               //do some action
          } else if("action9".equals(action)) {
               //do some action
          }

          /**
           * So, the next approach i tried it with switch
           * 1. Added each action as method and called those methods from the swith case statements
           */
          switch(action) {
          case "action1": action1();
               break;
          case "action2": action2();
               break;
          case "action3": action3();
               break;
          case "action4": action4();
               break;
          case "action5": action5();
               break;
          case "action6": action6();
               break;
          case "action7": action7();
               break;
          case "action8": action8();
               break;
          case "action9": action9();
               break;
          default:
               break;
          }

          /**
           * Still was not comfortable since i am doing un-necessary checks in one way or the other
           * So tried with [reflection][1] by invoking the action methods
           */
          Map<String, Method> methodMap = new HashMap<String, Method>();

        methodMap.put("action1", SampleClass.class.getMethod("action1"));
        methodMap.put("action2", SampleClass.class.getMethod("action2"));

        methodMap.get(action).invoke(null);  

       /**
        * But i am afraid of the following things while using reflection
        * 1. One is Security (Could any variable or methods despite its access specifier) - is reflection advised to use here?
        * 2. Reflection takes too much time than simple if else
        */

     }
    }

बेहतर पठनीयता और बेहतर कोड रखरखाव के लिए मेरे कोड में चेक / if-if सभी से बचने की आवश्यकता है। तो जैसे अन्य विकल्पों के लिए कोशिश की

1. स्विच केस - फिर भी यह मेरी कार्रवाई करने से पहले बहुत अधिक जांच करता है

2. प्रतिबिंब

i] एक मुख्य बात सुरक्षा है - जो मुझे इसकी पहुंच विनिर्देशक के बावजूद कक्षा के भीतर भी चर और विधियों का उपयोग करने की अनुमति देता है - मुझे यकीन नहीं है कि मौसम मैं अपने कोड में इसका उपयोग कर सकता हूं

ii] और दूसरा यह है कि अगर / तो-चेक की तुलना में सरल से अधिक समय लगता है

क्या कोई बेहतर दृष्टिकोण या बेहतर डिज़ाइन है जो कोई व्यक्ति उपरोक्त कोड को बेहतर तरीके से व्यवस्थित करने का सुझाव दे सकता है?

संपादित

मैंने नीचे दिए गए उत्तर पर विचार करते हुए उपरोक्त स्निपेट के लिए उत्तर जोड़ दिया है

लेकिन फिर भी, निम्न वर्ग "एक्सेकॉर्ला" और "एक्सकसोर्ब" कोड की केवल कुछ पंक्तियाँ करते हैं। क्या इसे एक विधि के रूप में जोड़ने की तुलना में एक वर्ग के रूप में जोड़ना एक अच्छा अभ्यास है? कृपया इस संबंध में सलाह दें।



2
आप 9 अलग-अलग कार्यों के साथ एक सर्वलेट को क्यों लोड कर रहे हैं? बस एक अलग सर्वलेट द्वारा समर्थित प्रत्येक क्रिया को किसी भिन्न पृष्ठ पर मैप क्यों नहीं किया जाता है? इस तरह से कार्रवाई का चयन क्लाइंट द्वारा किया जाता है और आपका सर्वर कोड क्लाइंट के अनुरोध को पूरा करने पर ध्यान केंद्रित करता है।
है_Factor

जवाबों:


13

पिछले उत्तर के आधार पर, जावा एनमों को गुण रखने की अनुमति देता है ताकि आप रणनीति पैटर्न को परिभाषित कर सकें, कुछ ऐसा

public enum Action {
    A ( () -> { //Lambda Sintax
        // Do A
       } ), 
    B ( () -> executeB() ), // Lambda with static method
    C (new ExecutorC()) //External Class 

    public Action(Executor e)
        this.executor = e;
    }

    //OPTIONAL DELEGATED METHOD
    public foo execute() {
        return executor.execute();
    }

    // Action Static Method
    private static foo executeB(){
    // Do B
    }
}

तब आपकी Executor(रणनीति) होगी

public interface Executor {
    foo execute();
}

public class ExecutorC implements Executor {
    public foo execute(){
        // Do C
    }
}

और आपके सभी / अगर आपके doPostतरीके में कुछ और बन जाते हैं

public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
    String action = req.getParameter("action");
    Action.valueOf(action).execute();
}

इस तरह से आप एनामों में निष्पादकों के लिए लैम्ब्डा का भी उपयोग कर सकते हैं।


अच्छी तरह से कहा .. लेकिन मैं एक छोटे से स्पष्टीकरण की जरूरत है .. मेरे सभी कार्यों action1 (), action2 () कोड की कुछ पंक्तियाँ होगी .. क्या इसे एक वर्ग के भीतर पैक करना अच्छा होगा?
टॉम टेलर

4
यह उन पंक्तियों की संख्या नहीं है जो आपको विशिष्ट कक्षाएं / ऑब्जेक्ट बनाने के लिए राजी करना चाहिए, लेकिन यह तथ्य कि वे विभिन्न व्यवहारों का प्रतिनिधित्व करते हैं। 1 विचार / अवधारणा = 1 तार्किक वस्तु।
मोगेनीमैन

2
@ राजसुबासुब्रमण्यन आप एक लंबोदर या विधि संदर्भ का उपयोग भी कर सकते हैं यदि आपको लगता है कि एक वर्ग बहुत भारी है। Executorएक कार्यात्मक इंटरफ़ेस है (या हो सकता है)।
हल्क

1
@ अद्यतन :) जब से मैं java7 में अब भी कर रहा हूँ मैं लैम्ब्डा अभिव्यक्ति का उपयोग नहीं कर सकता है के लिए J.Pichardo धन्यवाद .. तो, रणनीति पैटर्न के enum कार्यान्वयन पीछा किया पर यहाँ का सुझाव दिया dzone.com/articles/strategy-pattern-implemented
टॉम टेलर

1
@ राजसुबासुब्रमण्यम शांत, मैंने कुछ नया सीखा,
जे। पिचरो

7

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

इसके बजाय अर्थात:

      /**
       * Still was not comfortable since i am doing un-necessary checks in one way or the other
       * So tried with [reflection][1] by invoking the action methods
       */
      Map<String, Method> methodMap = new HashMap<String, Method>();

    methodMap.put("action1", SampleClass.class.getMethod("action1"));
    methodMap.put("action2", SampleClass.class.getMethod("action2"));

    methodMap.get(action).invoke(null);  

उपयोग

 public interface ProcessAction{
       public void process(...);
 }

प्रत्येक क्रिया के लिए उनमें से प्रत्येक को लागू करता है और फिर:

 // as attribute
Map<String, ProcessAction> methodMap = new HashMap<String, ProcessAction>();
// now you can add to the map you can either hardcode them in an init function
methodMap.put("action1",action1Process);

// but if you want some more flexibility you should isolate the map in a class dedicated :
// let's say ActionMapper and add them on init : 

public class Action1Manager{
    private static class ProcessAction1 implements ProcessAction{...}

    public Action1Manager(ActionMapper mapper){
       mapper.addNewAction("action1", new ProcessAction1());
    }
}

बेशक यह समाधान सबसे बड़ा नहीं है, इसलिए आपको उस लंबाई तक जाने की आवश्यकता नहीं हो सकती है।


मुझे लगता है कि ProcessActionइसके बजाय ऐसा होना चाहिए ActionProcess...?
टॉम टेलर

1
हां मैंने इसे ठीक किया।
वालफ्रैट

1
और, आम तौर पर, जवाब "ओओपी तंत्र का उपयोग करें" है। तो, यहां, आपको "स्थिति" और इसके संबंधित व्यवहार का पुनर्मूल्यांकन करना चाहिए। दूसरे शब्दों में, एक अमूर्त वस्तु द्वारा अपने तर्क का प्रतिनिधित्व करते हैं, और फिर अपने अंतर्निहित नट और बोल्ट के बजाय इस ऑब्जेक्ट को हेरफेर करते हैं।
मोगेनीमैन

इसके अलावा, @alfrat द्वारा प्रस्तावित दृष्टिकोण का एक प्राकृतिक विस्तार निर्दिष्ट स्ट्रिंग पैरामीटर के आधार पर सही प्रक्रियाएशन बनाने / वापस करने वाले कारखाने (सार) के प्रस्ताव में शामिल होगा।
मोगेनीमैन

@mgoeminne सही के बारे में ध्वनि
जे। Pichardo

2

कमांड पैटर्न का उपयोग करें , इसके लिए कमांड इंटरफ़ेस की आवश्यकता होगी जैसे कि:

interface CommandInterface {
    CommandInterface execute();
}

अगर Actionsबनाने में हल्के और सस्ते हैं तो फैक्ट्री मेथड का इस्तेमाल करें। प्रॉपर्टीज़ फ़ाइल से क्लासनेम को लोड करें जो actionName=classNameनिष्पादन के लिए निर्मित कार्यों के लिए मैप और एक साधारण फ़ैक्टरी विधि का उपयोग करता है।

    public Invoker execute(final String targetActionName) {
        final String className = this.properties.getProperty(targetAction);
        final AbstractCommand targetAction = (AbstractCommand) Class.forName(className).newInstance();
        targetAction.execute();
    return this;
}

यदि क्रियाएँ बनाना महंगा है, तो एक पूल का उपयोग करें, जैसे कि HashMap ; हालांकि ज्यादातर मामलों में मैं यह सुझाव देता हूं कि एकल जिम्मेदारी सिद्धांत के तहत बचा जा सकता है क्योंकि महंगे तत्व को कुछ पूर्व-निर्मित सामान्य संसाधन पूल के बजाय स्वयं कमांड के बजाय महंगे तत्व को सौंपना चाहिए।

    public class CommandMap extends HashMap<String, AbstractAction> { ... }

इसके बाद इन पर अमल किया जा सकता है

    public Invoker execute(final String targetActionName) {
        commandMap.get(targetActionName).execute();
        return this;
}

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


1

आप स्ट्रिंग मानों को हार्डकोड करने की आवश्यकता को कम करने के लिए गणना आधारित वस्तु का उपयोग कर सकते हैं। यह आपको कुछ समय बचाएगा और भविष्य में कोड को पढ़ने और विस्तारित करने के लिए बहुत साफ-सुथरा बनाता है।

 public static enum actionTypes {
      action1, action2, action3....
  }

  public void doPost {
      ...
      switch (actionTypes.valueOf(action)) {
          case action1: do-action1(); break;
          case action2: do-action2(); break;
          case action3: do-action3(); break;
      }
  }

1

फैक्ट्री मेथड पैटर्न वह है जो मुझे दिखता है यदि आप स्केलेबल और कम रख-रखाव डिजाइन की तलाश कर रहे हैं।

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

 abstract class action {abstract doStuff(action)}

action1, action2 ........ doNuff के साथ एक्शनएन ठोस कार्यान्वयन विधि को लागू करने वाली चीज़।

बस कॉल करना

    action.doStuff(actionN)

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


टाइपो एब्स्ट्रैक्ट -> पहली कोड लाइन में सार। कृपया संपादित करें। इसके अलावा, क्या आप इस उदाहरण को फ्लश करने के लिए थोड़ा और अधिक कोड जोड़ सकते हैं और अधिक सीधे दिखाने के लिए कि यह ओपी के प्रश्न का उत्तर कैसे देता है?
जे एलस्टन

0

@ जे के संदर्भ में। Pichardo उत्तर मैं उपरोक्त स्निपेट को निम्नलिखित के रूप में संशोधित कर रहा हूं

public class SampleClass extends HttpServlet {

public enum Action {
    A (new ExecutorA()),
    B (new ExecutorB())

    Executor executor;

    public Action(Executor e)
        this.executor = e;
    }

    //The delegate method
    public void execute() {
        return executor.execute();
    }
}

public foo Executor {
    foo execute();
}

public class ExecutorA implements Executor{
   public void execute() {
      //Do some action
   }
}

public class ExecutorB implements Executor{
   public void execute() {
      //Do some action
   }
}

public void doPost(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException {

  String action = req.getParameter("action"); 
  Action.valueOf(action).execute();
  }
}

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