IT

자바의 긴 if 문 목록

lottoking 2020. 8. 20. 19:06
반응형

자바의 긴 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

다음 그런 Map<String,Command>개체 를 빌드하고 Command인스턴스로 채 웁니다 .

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

그런 다음 if / else if 체인을 다음으로 바꿀 수 있습니다 .

commandMap.get(value).exec();

편집하다

당신은 또한 다음과 같은 특별한 명령을 추가 할 수 있습니다. UnknownCommand또는 NullCommand,하지만 당신은 필요하기 CommandMap위해 핸들이 코너의 경우 클라이언트의 검사를 최소화 할 수 있습니다.


내 제안은 enum과 Command의 가벼운 조합입니다. 이 효과적인 Java의 항목 30에서 Joshua Bloch가 권장하는 관용구입니다.

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을 사용하는 대신 열거 형을 유지하고 열거 형 내에서 구현 클래스에 대한 호출을 포함 할 수 있음). 이 질문에 대한 Andreas 또는 jens의 답변을 참조하십시오.


dfa에 의해 간단하고 명확하게 된대로 인터페이스를 구현하는 것이 깨끗하고 우아합니다 (그리고 "공식적으로"지원되는 방식). 이것이 인터페이스 개념의 의미입니다.

C #에서는 c에서 functon 포인터를 사용하려는 프로그래머를 위해 대리 튼 사용할 수 있습니다 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();

글쎄, 나는 명령을 생성하고 문자열을 키로 사용하여 해시 맵에 넣는 것이 좋습니다.


명령 패턴 접근 방식 최선의 방법에 더 가깝고 장기적으로 유지 관리 할 수 ​​있다고 생각하고 여기에 한 줄 옵션이 있습니다.

org.apache.commons.beanutils.MethodUtils.invokeMethod (this, "doCommand"+ 값, null);


나는 보통 그렇게 노력합니다.

public enum Command {

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

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

abstract void exec();
 }

이 많은 장점이 있습니다.

1) exec를 구현하지 않고 열거 형을 추가 할 수 없습니다. 그래서 당신은 A를 놓치지 않을 것입니다.

2) 명령 맵에 추가하지 않는 구성 맵을 구축하기위한 상용구 코드가 없습니다. 확장 인 방법과 그 구현. (논문의 여지가 상용구이기도하지만 더 짧아지지 않을 것입니다.)

3) if의 긴 목록을보고 보거나 hashCode를 계산하고 조회를 수행 할 수있는 CPU 사이클을 저장합니다.

편집 : enum이 없지만 소스로 Command.valueOf(mystr).exec()있으면 exec 메소드를 호출하는 데 사용 합니다. 다른 패키지에서 호출하려는 execif에 public 한정 매혹합니다.


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

그러나 당신은 당신을 처리하기 위해 이것들의 세트를 가지고 있습니까? 그런 다음 Enum으로 수행하는 것이 좋습니다.

"값"을 확인하기 위해 Enum에 메서드를 추가하는 경우 스위치를 사용하지 않고 사용할 수 있습니다 (예제에서 getter가 필요하지 않을 수 있음). 그런 다음 다음을 수행 할 수 있습니다.

업데이트 : 각 호출에서 반복을 피하기 위해 정적 맵을 추가했습니다. 이 답변 에서 뻔뻔스럽게 꼬집었습니다 .

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 을 사용하는 중이고 Lambda를 사용하려는 경우에 대비 하여 가지 니펫 제공 하고 있습니다!

매개 변수가없는 명령 :

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

위의 예에서는 ( 이 예에서 이름 지정된) Object를 인수로 취하는의 클래스 doSomethingX에있는 메서드 입니다.myObjparam


여러 개의 내재 된 'if'문이있는 경우 이는 규칙 엔진 을 사용하기위한 패턴입니다 . 예를 들어 JBOSS Drools 를 참조하십시오 .


여기에 설명 된대로 HashMap을 사용하십시오.


일련의 프로 시저 (명령이라고 부르는 것)를 가질 수 있다면 유용 할 것입니다 ..

하지만 코드를 작성하는 프로그램을 작성할 수 있습니다. 모두 매우 체계적입니다. if (value = 'A') commandA (); else if (........................ etc


다양한 명령의 동작 사이에 겹치는 부분이 있는지 확실하지 않지만 여러 명령이 일부 입력 값을 처리하도록 허용하여 더 많은 유연성을 제공 할 수있는 책임사슬 패턴을 살펴볼 수도 있습니다.


명령 패턴은 갈 길입니다. 다음은 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

반응형