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
'IT' 카테고리의 다른 글
Mac OSX에서의 Mysql 5.6 문제 (0) | 2022.12.27 |
---|---|
JAVA_의 설정 방법Mac에서 영구적으로 홈? (0) | 2022.12.27 |
SQL: 프리픽스가 있는 테이블 삭제 (0) | 2022.12.27 |
Python을 사용하여 touch를 구현하시겠습니까? (0) | 2022.12.27 |
할당 후 예기치 않게 변경되지 않도록 목록을 복제하려면 어떻게 해야 합니까? (0) | 2022.12.27 |