从工厂请求项目,而无需对每种情况进行硬编码

问题描述 投票:1回答:3

我有一个称为Command的界面:

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 {...}

而工厂应该采用String并返回相应命令的实例:

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进行编码?

java class interface factory hardcode
3个回答
1
投票

生成标准名称(package.class)并调用

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

然后打电话

myClass.newInstance();

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
        }
    }
}

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;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.