Ste*_*eve 100 java design-patterns command-pattern
对不起,我找不到回答这个问题的问题,我几乎可以肯定其他人已经提出了这个问题.
我的问题是我正在编写一些系统库来运行嵌入式设备.我有命令可以通过无线电广播发送到这些设备.这只能通过文字来完成.在系统库中我有一个线程来处理看起来像这样的命令
if (value.equals("A")) { doCommandA() }
else if (value.equals("B")) { doCommandB() }
else if etc.
Run Code Online (Sandbox Code Playgroud)
问题是它有很多命令会迅速失控.看起来很可怕,调试很痛苦,并且在几个月的时间里难以理解.
dfa*_*dfa 169
使用命令模式:
public interface Command {
void exec();
}
public class CommandA() implements Command {
void exec() {
// ...
}
}
// etc etc
Run Code Online (Sandbox Code Playgroud)
然后构建一个Map<String,Command>对象并用Command实例填充它:
commandMap.put("A", new CommandA());
commandMap.put("B", new CommandB());
Run Code Online (Sandbox Code Playgroud)
然后你可以用以下代码替换你的if/else if链:
commandMap.get(value).exec();
Run Code Online (Sandbox Code Playgroud)
编辑
您还可以添加特殊命令,例如UnknownCommand或NullCommand,但您需要一个CommandMap处理这些极端情况的命令,以便最大限度地减少客户的检查.
jen*_*ens 12
我的建议是enum和Command对象的轻量级组合.这是Joshua Bloch在Effective Java第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();
}
Run Code Online (Sandbox Code Playgroud)
当然,您可以将参数传递给doCommand或具有返回类型.
如果doCommand的实现并不真正"适合"枚举类型,那么这个解决方案可能不太合适,这就像往常一样,当你必须做出权衡时 - 有点模糊.
有一个命令枚举:
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;
}
Run Code Online (Sandbox Code Playgroud)
如果您有多个命令,请查看使用Command模式,如其他地方所述(尽管您可以保留枚举并将调用嵌入枚举中的实现类,而不是使用HashMap).有关示例,请参阅Andreas或jens对此问题的回答.
dfa简洁明了地演示了一个简洁明了的界面(以及"正式"支持的方式).这就是界面概念的意义所在.
在C#中,我们可以为喜欢在c中使用functon指针的程序员使用委托,但DFA的技术是使用方法.
你也可以有一个数组
Command[] commands =
{
new CommandA(), new CommandB(), new CommandC(), ...
}
Run Code Online (Sandbox Code Playgroud)
然后你可以通过索引执行命令
commands[7].exec();
Run Code Online (Sandbox Code Playgroud)
从DFA抄袭,但有一个抽象的基类而不是接口.注意稍后将使用的cmdKey.根据经验,我意识到设备命令经常也有子命令.
abstract public class Command()
{
abstract public byte exec(String subCmd);
public String cmdKey;
public String subCmd;
}
Run Code Online (Sandbox Code Playgroud)
这样构造你的命令,
public class CommandA
extends Command
{
public CommandA(String subCmd)
{
this.cmdKey = "A";
this.subCmd = subCmd;
}
public byte exec()
{
sendWhatever(...);
byte status = receiveWhatever(...);
return status;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以通过提供键值对吸引功能来扩展通用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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后构建您的命令库:
CommandHash commands =
new CommandHash(
{
new CommandA("asdf"),
new CommandA("qwerty"),
new CommandB(null),
new CommandC("hello dolly"),
...
});
Run Code Online (Sandbox Code Playgroud)
现在你可以客观地发送控件
commands.get("A").exec();
commands.get(condition).exec();
Run Code Online (Sandbox Code Playgroud)