이 질문에 대한 답을 찾을 수 없어서 죄송합니다. 다른 사람이 이전에 질문을 제기 한 것 같습니다.
내 문제는 임베디드 장치를 실행하기 위해 일부 시스템 라이브러리를 작성하고 있다는 것입니다. 라디오 방송을 통해 이러한 장치로 보낼 수있는 명령이 있습니다. 이것은 텍스트로만 수행 할 수 있습니다. 시스템 라이브러리 내부에는 다음과 같은 명령을 처리하는 스레드가 있습니다.
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 객체의 가벼운 조합입니다. 이것은 Effective 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;
}
몇 개 이상의 명령이있는 경우 다른 곳에서 대답 한대로 Command 패턴을 사용하는 것이 좋습니다 (HashMap을 사용하는 대신 enum을 유지하고 enum 내에 구현 클래스에 대한 호출을 포함 할 수 있음). 이 질문에 대한 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();
답변
글쎄, 나는 명령 객체를 만들고 String as Key를 사용하여 해시 맵에 넣는 것이 좋습니다.
답변
명령 패턴 접근 방식이 최선의 방법에 더 가깝고 장기적으로 유지 관리 할 수 있다고 생각하더라도 여기에 한 가지 라이너 옵션이 있습니다.
org.apache.commons.beanutils.MethodUtils.invokeMethod (this, “doCommand”+ value, 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 한정자를 사용해야합니다.