IT

Java의 if 문의 긴 목록

itgroup 2022. 12. 27. 21:15
반응형

Java의 if 문의 긴 목록

죄송합니다. 이 질문에 대한 답을 찾을 수 없습니다. 다른 사람이 이전에 문제를 제기한 적이 있을 것입니다.

문제는 임베디드 디바이스를 실행하기 위해 시스템 라이브러리를 쓰는 것입니다.라디오 방송을 통해 이러한 장치에 보낼 수 있는 명령어를 가지고 있습니다.이것은 텍스트로만 가능합니다.시스템 라이브러리 내부에 다음과 같은 명령을 처리하는 스레드가 있습니다.

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

문제는 명령어가 너무 많아서 빠르게 제어 불능 상태가 될 수 있다는 것입니다.밖을 내다보는 것도 끔찍하고 디버깅하는 것도 고통스럽고 몇 달 안에 이해하기가 너무 힘들어요.

명령 패턴 사용:

public interface Command {
     void exec();
}

public class CommandA() implements Command {

     void exec() {
          // ... 
     }
}

// etc etc

, a를 Map<String,Command>.Command★★★★★★★★★★★★★★★★★★:

commandMap.put("A", new CommandA());
commandMap.put("B", new CommandB());

if/schain을 다음과 같이 교환할 수 있습니다.

commandMap.get(value).exec();

편집

'하다, 하다, 하다, 하다'와 같은 도 있습니다.UnknownCommand ★★★★★★★★★★★★★★★★★」NullCommand, ,가 CommandMap고객의 체크를 최소화하기 위해 이러한 코너 케이스를 처리합니다.

enum 객체와 Command 객체의 가벼운 조합이 제안됩니다.이것은 조슈아 블로흐가 효과적인 자바 항목 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();
}

물론 매개 변수를 doCommand에 전달하거나 반환 유형을 지정할 수 있습니다.

doCommand의 구현이 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;
}

여러 개의 명령어가 있는 경우 다른 답변에 따라 명령어패턴을 사용하는 것을 검토해 주십시오(HashMap을 사용하는 대신 열거형을 유지하고 열거형 내의 구현 클래스에 콜을 포함할 수 있습니다).이 질문에 대한 안드레아스나 젠스의 답변을 예로 들어주세요.

dfa에 의해 심플하고 알기 쉬운 인터페이스 구현은 깨끗하고 우아합니다(및 "공식적으로" 지원되는 방식).이것이 인터페이스 개념의 목적입니다.

C#에서는 c에서 펑튼 포인터를 사용하는 프로그래머에게 위임자를 사용할 수 있지만, DFA의 기술이 사용 방법입니다.

어레이를 사용할 수도 있습니다.

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

그러면 인덱스로 명령을 실행할 수 있습니다.

commands[7].exec();

DFA를 표절했지만 인터페이스가 아닌 추상적인 기본 클래스가 있습니다.나중에 사용되는 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;
  }
}

다음으로 키와 값의 쌍 흡인 기능을 제공함으로써 범용 HashMap 또는 HashTable을 확장할 수 있습니다.

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();

명령어 오브젝트를 생성하여 String as Key를 사용하여 해시맵에 넣을 것을 권장합니다.

커맨드 패턴의 어프로치가 베스트 프라이스를 지향해 장기적으로 유지보수가 가능하다고 생각되더라도, 다음과 같은 옵션이 있습니다.

org.contractions.beanutils.MethodUtils.invokeMethod(이것, doCommand"+value,null);

저는 보통 그런 식으로 해결하려고 합니다.

public enum Command {

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

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

abstract void exec();
 }

여기에는 많은 이점이 있습니다.

1) exec을 구현하지 않으면 열거형을 추가할 수 없습니다.A를 놓치지 않도록.

2) 명령어 맵에 추가할 필요도 없기 때문에 맵을 빌드하기 위한 보일러 플레이트 코드는 없습니다.단지 추상적인 방법과 그 구현일 뿐입니다.(보일러플레이트이기도 하지만 더 짧아지지는 않을 것입니다.)

3) if의 긴 목록을 확인하거나 hashCodes를 계산하여 조회함으로써 낭비되는 CPU 사이클을 절약할 수 있습니다.

소스로 edit: enum 을 사용합니다.Command.valueOf(mystr).exec() 다른.다른 패키지에서 호출하려면 exec에서 공용 수식자를 사용해야 합니다.

명령어 맵을 사용하는 것이 가장 좋습니다.

하지만 당신은 이것들 한 세트를 가지고 있어서 결국 많은 지도들이 여기저기 돌아다니게 되는 건가요?그렇다면 에넘스와 함께 하는 것이 가치가 있다.

Enum에 메서드를 추가하여 "value"를 해결하면 스위치를 사용하지 않고 Enum을 사용할 수 있습니다(이 예에서는 getters가 필요하지 않을 수 있습니다).그러면 다음 작업을 수행할 수 있습니다.

업데이트: 각 콜에서의 반복을 피하기 위해 스태틱 맵이 추가되었습니다.뻔뻔스럽게도 이 대답에서 꼬집었다.

Commands.getCommand(value).exec();

public interface Command {
    void exec();
}

public enum Commands {
    A("foo", new Command(){public void exec(){
        System.out.println(A.getValue());
    }}),
    B("bar", new Command(){public void exec(){
        System.out.println(B.getValue());
    }}),
    C("barry", new Command(){public void exec(){
        System.out.println(C.getValue());
    }});

    private String value;
    private Command command;
    private static Map<String, Commands> commandsMap;

    static {
        commandsMap = new HashMap<String, Commands>();
        for (Commands c : Commands.values()) {
            commandsMap.put(c.getValue(), c);    
        }
    }

    Commands(String value, Command command) {
        this.value= value;
        this.command = command;
    }

    public String getValue() {
        return value;
    }

    public Command getCommand() {
        return command;
    }

    public static Command getCommand(String value) {
        if(!commandsMap.containsKey(value)) {
            throw new RuntimeException("value not found:" + value);
        }
        return commandsMap.get(value).getCommand();
    }
}

@dfa의 답변이 최선의 해결책이라고 생각합니다.

Java 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();

(명령어 대신 실행 가능(Runnable)을 사용할 수 있지만 의미적으로는 적절하지 않다고 생각합니다).

하나의 매개 변수를 사용하는 명령:

사용할 수 .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' 문이 여러 개 있는 경우 규칙 엔진을 사용하기 위한 패턴입니다.를 들어 JBOSS Drools를 참조하십시오.

다음 설명에 따라 HashMap을 사용합니다.

일련의 프로시저(커맨드라고 부르는 것)가 있으면 편리합니다.

코드를 쓸 수 있는 프로그램을 만들 수도 있어요(value=')의 경우 모두 매우 체계적입니다.A') 명령어 A(). 그렇지 않으면 if(..................................e.t.c.

다양한 명령어 동작 사이에 중복되는 부분이 있는지 잘 모르겠지만, 여러 명령어가 일부 입력값을 처리할 수 있도록 함으로써 유연성을 높일 수 있는 Chain Of Responsibility 패턴도 살펴보시기 바랍니다.

명령어 패턴이 가장 중요합니다.다음으로 Java 8을 사용하는 예를 제시하겠습니다.

1. 인터페이스를 정의합니다.

public interface ExtensionHandler {
  boolean isMatched(String fileName);
  String handle(String fileName);
}

2. 각 확장자를 사용하여 인터페이스를 구현합니다.

public class PdfHandler implements ExtensionHandler {
  @Override
  public boolean isMatched(String fileName) {
    return fileName.endsWith(".pdf");
  }

  @Override
  public String handle(String fileName) {
    return "application/pdf";
  }
}

그리고.

public class TxtHandler implements ExtensionHandler {
  @Override public boolean isMatched(String fileName) {
    return fileName.endsWith(".txt");
  }

  @Override public String handle(String fileName) {
    return "txt/plain";
  }
}

기타 등등..

3. 클라이언트의 정의:

public class MimeTypeGetter {
  private List<ExtensionHandler> extensionHandlers;
  private ExtensionHandler plainTextHandler;

  public MimeTypeGetter() {
    extensionHandlers = new ArrayList<>();

    extensionHandlers.add(new PdfHandler());
    extensionHandlers.add(new DocHandler());
    extensionHandlers.add(new XlsHandler());

    // and so on

    plainTextHandler = new PlainTextHandler();
    extensionHandlers.add(plainTextHandler);
  }

  public String getMimeType(String fileExtension) {
    return extensionHandlers.stream()
      .filter(handler -> handler.isMatched(fileExtension))
      .findFirst()
      .orElse(plainTextHandler)
      .handle(fileExtension);
  }
}

4. 다음은 샘플 결과입니다.

  public static void main(String[] args) {
    MimeTypeGetter mimeTypeGetter = new MimeTypeGetter();

    System.out.println(mimeTypeGetter.getMimeType("test.pdf")); // application/pdf
    System.out.println(mimeTypeGetter.getMimeType("hello.txt")); // txt/plain
    System.out.println(mimeTypeGetter.getMimeType("my presentation.ppt")); // "application/vnd.ms-powerpoint"
  }

많은 것을 할 수 있다면, 많은 코드가 있을 것이고, 당신은 그것으로부터 정말 벗어날 수 없습니다.쉽게 팔로우하고 변수 이름을 의미 있게 지정하면 코멘트도 도움이 됩니다.

언급URL : https://stackoverflow.com/questions/1199646/long-list-of-if-statements-in-java

반응형