重构java代码

时间:2010-03-31 20:15:11

标签: java refactoring

好的猜测这个问题看起来很像:

What is the best way to replace or substitute if..else if..else trees in programs?

考虑这个问题已关闭!


我想重构看起来像这样的代码:

String input; // input from client socket.
if (input.equals(x)) {
  doX();
} else if (input.equals(y)) {
  doY();
} else {
  unknown_command();
}

是检查来自套接字的输入以执行某些操作的代码,但我不喜欢if else构造,因为每次向服务器(代码)添加新命令时都必须使用新的if添加哪个是丑陋的。删除命令时,还必须修改if else

5 个答案:

答案 0 :(得分:8)

使用Map<String, Command>方法Command interface execute()收集这些命令。

Map<String, Command> commands = new HashMap<String, Command>();
// Fill it with concrete Command implementations with `x`, `y` and so on as keys.

// Then do:
Command command = commands.get(input);
if (command != null) {
    command.execute();
} else {
    // unknown command.
}

为了更进一步,您可以考虑通过扫描实现特定接口(在本例中为Command)或类路径中的特定注释的类来动态填充地图。 Google Reflections可能对此有所帮助。

更新(来自评论)您还可以考虑将answer of Instantsoup与我的答案相结合。在buildExecutor()方法期间,首先从Map获取命令,如果Map中不存在该命令,则尝试加载关联的类并将其放入{{1} }}。懒加载的排序。这比在我的回答中扫描整个类路径更有效,并且每次都像在Instantsoup的回答中那样创建它。

答案 1 :(得分:3)

一种方法是使接口ICommand成为命令的一般合同,例如:

public interface ICommand {
    /** @param context The command's execution context */
    public void execute(final Object context);
    public String getKeyword();
}

然后您可以使用Java的SPI机制自动发现您的各种实现,并在Map<String,ICommand>中注册,然后执行knownCommandsMap.get(input).execute(ctx)或类似的事情。

这实际上使您能够将服务与命令实现分离,从而有效地使这些服务可插入。

通过添加一个名为ICommand类的完全限定名称的文件来完成向SPI注册实现类(因此,如果它在包中,则文件将在类路径中为META-INF/dummy.ICommand),并且然后你将加载并注册为:

final ServiceLoader<ICommand> spi = ServiceLoader.load(ICommand.class);
for(final ICommand commandImpl : spi)
    knownCommandsMap.put(commandImpl.getKeyword(), commandImpl);

答案 2 :(得分:3)

界面,工厂和反思怎么样?您仍然需要处理错误输入的异常,但您总是需要这样做。使用此方法,您只需为新输入添加Executor的新实现。

public class ExecutorFactory
{
    public static Executor buildExecutor(String input) throws Exception
    {
        Class<Executor> forName = (Class<Executor>) Class.forName(input);
        return (Executor) executorClass.newInstance();
    }
}

public interface Executor
{
    public void execute();
}


public class InputA implements Executor
{
    public void execute()
    {
        // do A stuff
    }
}

public class InputB implements Executor
{
    public void execute()
    {
        // do B stuff
    }
}

您的代码示例将变为

String input;
ExecutorFactory.buildExecutor(input).execute();

答案 3 :(得分:2)

在枚举类上构建命令模式可以减少一些样板代码。我们假设input.equals(x)中的x是“XX”而input.equals(y)中的y是“YY”

enum Commands {
   XX {
     public void execute() { doX(); }        
   },
   YY {
     public void execute() { doY(); }        
   };

   public abstract void execute();
}

String input = ...; // Get it from somewhere

try {
  Commands.valueOf(input).execute();
}
catch(IllegalArgumentException e) {
   unknown_command();
}

答案 4 :(得分:1)

你说你正在处理来自套接字的输入。多少输入?这有多复杂?结构如何?

根据这些问题的答案,您可能最好不要编写语法,并让解析器生成器(例如ANTLR)生成输入处理代码。