java - जावा में बयानों की लंबी सूची




design-patterns command-pattern (10)

@ डीएफए द्वारा प्रदान किया गया उत्तर मेरी राय में सबसे अच्छा समाधान है।

यदि आप जावा 8 का उपयोग कर रहे हैं और Lambdas का उपयोग करना चाहते हैं तो मैं बस कुछ स्निपेट प्रदान कर रहा हूं!

पैरामीटर के बिना कमांड:

Map<String, Command> commands = new HashMap<String, Command>();
commands.put("A", () -> System.out.println("COMMAND A"));
commands.put("B", () -> System.out.println("COMMAND B"));
commands.put("C", () -> System.out.println("COMMAND C"));
commands.get(value).exec();

(आप कमांड के बजाए रननेबल का उपयोग कर सकते हैं, लेकिन मैं इसे अर्थात् सही तरीके से नहीं मानता):

एक पैरामीटर के साथ कमांड:

यदि आप पैरामीटर की अपेक्षा करते हैं तो आप java.util.function.Consumer उपयोग कर सकते हैं। java.util.function.Consumer :

Map<String, Consumer<Object>> commands = new HashMap<String, Consumer<Object>>();
commands.put("A", myObj::doSomethingA);
commands.put("B", myObj::doSomethingB);
commands.put("C", myObj::doSomethingC);
commands.get(value).accept(param);

उपर्युक्त उदाहरण में, doSomethingX एक विधि है जो myObj की कक्षा में मौजूद है जो तर्क के रूप में कोई ऑब्जेक्ट (इस उदाहरण में param नामित) लेता है।

क्षमा करें मुझे इसका जवाब देने वाला कोई प्रश्न नहीं मिल रहा है, मैं लगभग निश्चित हूं कि किसी और ने इसे पहले उठाया है।

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

if (value.equals("A")) { doCommandA() }
else if (value.equals("B")) { doCommandB() } 
else if etc. 

समस्या यह है कि इसमें बहुत सारे आदेश हैं जो नियंत्रण से बाहर कुछ सर्पिल हो जाएंगे। देखने के लिए भयानक, कुछ महीनों के समय में समझने के लिए परेशान करने और परेशान करने के लिए दर्दनाक।


आदेशों का एक enum है:

public enum Commands { A, B, C; }
...

Command command = Commands.valueOf(value);

switch (command) {
    case A: doCommandA(); break;
    case B: doCommandB(); break;
    case C: doCommandC(); break;
}

यदि आपके पास कुछ कमांड हैं, तो कमांड पैटर्न का उपयोग करके देखें, जैसा कि कहीं और उत्तर दिया गया है (हालांकि आप enash को बनाए रख सकते हैं और हैश मैप का उपयोग करने के बजाय enum के भीतर कार्यान्वयन कक्षा में कॉल एम्बेड कर सकते हैं)। उदाहरण के लिए कृपया इस प्रश्न के लिए एंड्रियास या जेन्स का जवाब देखें।


खैर, मैं कमांड ऑब्जेक्ट्स बनाने का सुझाव देता हूं और स्ट्रिंग के रूप में स्ट्रिंग का उपयोग करके उन्हें हैशैप में डाल देता हूं।


डीएफए द्वारा आसानी से और स्पष्ट रूप से प्रदर्शित एक इंटरफेस को कार्यान्वित करना स्वच्छ और सुरुचिपूर्ण (और "आधिकारिक तौर पर" समर्थित तरीका है)। यह इंटरफेस अवधारणा के लिए क्या मतलब है।

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

आपके पास एक सरणी भी हो सकती है

Command[] commands =
{
  new CommandA(), new CommandB(), new CommandC(), ...
}

फिर आप इंडेक्स द्वारा कमांड निष्पादित कर सकते हैं

commands[7].exec();

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

abstract public class Command()
{
  abstract public byte exec(String subCmd);
  public String cmdKey;
  public String subCmd;
}

इस प्रकार अपने आदेशों का निर्माण,

public class CommandA
extends Command
{
  public CommandA(String subCmd)
  {
    this.cmdKey = "A";
    this.subCmd = subCmd;
  }

  public byte exec()
  {
    sendWhatever(...);
    byte status = receiveWhatever(...);
    return status;
  }
}

फिर आप कुंजी-मूल्य जोड़ी चूसने वाले फ़ंक्शन प्रदान करके जेनेरिक हैश मैप या हैशटेबल का विस्तार कर सकते हैं:

public class CommandHash<String, Command>
extends HashMap<String, Command>
(
  public CommandHash<String, Command>(Command[] commands)
  {
    this.commandSucker(Command[] commands);
  }
  public commandSucker(Command[] commands)
  {
    for(Command cmd : commands)
    {
      this.put(cmd.cmdKey, cmd);
    }
  }
}

फिर अपने कमांड स्टोर का निर्माण करें:

CommandHash commands =
  new CommandHash(
  {
    new CommandA("asdf"),
    new CommandA("qwerty"),
    new CommandB(null),
    new CommandC("hello dolly"),
    ...
  });

अब आप सामूहिक रूप से नियंत्रण भेज सकते हैं

commands.get("A").exec();
commands.get(condition).exec();

मेरा सुझाव enum और कमांड ऑब्जेक्ट का हल्का संयोजन होगा। प्रभावशाली जावा के आइटम 30 में जोशुआ ब्लोच द्वारा अनुशंसित यह एक मुहावरे है।

public enum Command{
  A{public void doCommand(){
      // Implementation for A
    }
  },
  B{public void doCommand(){
      // Implementation for B
    }
  },
  C{public void doCommand(){
      // Implementation for C
    }
  };
  public abstract void doCommand();
}

बेशक आप कमांड करने के लिए पैरामीटर पास कर सकते हैं या वापसी प्रकार हैं।

यह समाधान वास्तव में उपयुक्त नहीं हो सकता है यदि डॉक कॉमांड के कार्यान्वयन वास्तव में enum प्रकार के लिए "फिट" नहीं होते हैं, जो सामान्य रूप से आपको ट्रेडऑफ करना होता है - थोड़ा अस्पष्ट।


मैं आमतौर पर इसे हल करने की कोशिश करता हूं:

public enum Command {

A {void exec() {
     doCommandA();
}},

B {void exec() {
    doCommandB();
}};

abstract void exec();
 }

इसमें कई फायदे हैं:

1) निष्पादन लागू किए बिना एक enum जोड़ने के लिए संभव नहीं है। तो आप ए को याद नहीं करेंगे

2) आपको इसे किसी भी कमांड मैप में भी जोड़ना नहीं होगा, इसलिए नक्शा बनाने के लिए कोई बॉयलरप्लेट कोड नहीं है। सिर्फ सार विधि और इसके कार्यान्वयन। (जो तर्कसंगत रूप से बॉयलरप्लेट भी है, लेकिन इसे कोई छोटा नहीं मिलेगा ..)

3) यदि आप हैशकोड की गणना और लुकअप करने की लंबी सूची के माध्यम से किसी भी बर्बाद सीपीयू चक्रों को बचाएंगे।

संपादित करें: यदि आपके पास enums नहीं है लेकिन स्रोत के रूप में तार हैं, तो exec विधि को कॉल करने के लिए बस Command.valueOf(mystr).exec() का उपयोग करें। ध्यान दें कि आपको बहिष्कृत पर सार्वजनिक संशोधक का उपयोग करना होगा जिसे आप इसे दूसरे पैकेज से कॉल करना चाहते हैं।


यदि प्रक्रियाओं की एक सरणी (जिसे आप कमांड कहते हैं) होना संभव था जो उपयोगी होगा ..

लेकिन आप अपना कोड लिखने के लिए एक प्रोग्राम लिख सकते हैं। यह सब बहुत व्यवस्थित है अगर (मूल्य = 'ए') कमांड ए (); अन्यथा अगर (....................... आदि


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



वैसे एक कमांड पैटर्न है लेकिन आप जो भी कर रहे हैं उसके लिए यह अधिक हो सकता है। KISS याद रखें।







command-pattern