1

我有一个名为命令的接口:

public interface Command {
// irrelevant code
}

大约有 15 个类实现了这个接口:

public class Comm_A implements Command {
// irrelevant code
}

public class Comm_B implements Command {...}
....
public class Comm_XZ implements Command {...}

工厂应该接受一个字符串并返回相应命令的一个实例:

public class CommandFactory {
    public static Command getCommand(String s) {
        if (s.equals("Comm_A")) return new Comm_A();
        else ... // each particular case
    }
}

考虑到我希望能够在不更改工厂代码的情况下添加新命令。

我可以让它自动尝试创建相应的实例,而无需对每个“Comm_A”...“Comm_XZ”案例进行硬编码并且不使用 java.lang.reflect 吗?

4

3 回答 3

1

生成完全限定名称(package.class)并调用

Class<?> myClass = Class.forName(className);

然后打电话

myClass.newInstance();
于 2015-11-25T13:49:49.900 回答
1

如果您的命令是无状态的、线程安全的对象,您可以创建一个急切创建的实例的映射并重复使用这些实例:

public class CommandFactory {
    private final Map<String, Command> availableCommands;

    public CommandFactory(Map<String, Command> availableCommands) {
        this.availableCommands = availableCommands;
    }

    public Command getCommand(String s) {
        if (availableCommands.contains(s) {
            return availableCommands.get(s);
        } else {
            // handle error state
        }
    }
}

为了这有任何好处(并满足“不更改类”的要求)但是工厂不会是一个静态类,具有实例(而不是静态)getCommand()方法。然后可以使用 DI 框架注入可用的命令。


如果您需要为每个调用创建一个新的实现实例,那么如果不使用可怕的链Command,您就无法真正避免反射。if...else if不过,我不会太担心在这种情况下使用它,它的Class.newInstance()可读性很强,而且效率也不是很低。

尽管如此,我仍然会坚持使用这种地图方法,以使其灵活且可通过配置进行扩展。代码将与 类似Map<String, Class>return availableCommands.get(s).newInstance()以及更多的异常检查。


第三种可能的方法是为每个命令类型创建一个单独的工厂类,并Map<String, SpecificCommandFactory>使用样板代码并且可能非常不可读,因此仅在您确实需要将工厂可用的命令分开时才适用:

public iterface SpecificCommandFactory {
    Command createCommand();
}

public class Comm_AFactory implements SpecificCommandFactory {
    public Comm_A createCommand() {
        return new Comm_A();
    }
}

public class CommandFactory {
    private final Map<String, SpecificCommandFactory> availableCommands;

    public CommandFactory(Map<String, Command> availableCommands) {
        this.availableCommands = availableCommands;
    }

    public Command getCommand(String s) {
        if (availableCommands.contains(s) {
            return availableCommands.get(s).createCommand();
        } else {
            // handle error state
        }
    }
}
于 2015-11-25T13:54:47.993 回答
0

您可以为此使用某种委托工厂。您可以为不同的命令保存工厂,而不是在地图中保存对对象的引用(如 Jiri Tousek 的回答):

public class CommandFactory{
    private static final Map<String, Callable<Command>> commands = new HashMap<>();
    public static void registerCommand(String command, Callable<Command> factory){
        commands.put(command, factory);
    }
    public static Command getCommand(String command){
        Callable<Command> factory = commands.get(command);
        if(factory != null){
            return factory.call();
        }
        return null;
    }
}
于 2015-11-25T14:09:37.567 回答