具有静态工厂方法或构造函数的工厂模式

时间:2016-03-09 15:08:15

标签: java design-patterns constructor factory

我有一个类RequestParams的层次结构,所有类都可以使用ExtArgs创建。

public interface RequestParams {
}

我还创建了一个工厂RequestsFactory,如下所示:

public class RequestFactory<P extends RequestParams> {

    private final Logger logger = LoggerFactory.getLogger(RequestFactory.class);
    final Class<P> paramsClass;

    public RequestFactory(Class<P> paramsClass) {
        this.paramsClass = paramsClass;
    }

    public Request<P> create(ExternalArgs args)  {
        P params = null;
        try {
            params = paramsClass.getDeclaredConstructor(ExternalArgs.getClass()).newInstance(args);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            logger.error("Failed to generate request", e);
        }
        return new Request<>("get", Collections.singletonList(params));
    }

    static <P extends RequestParams> RequestFactory<P> createFactory(
            final Class<P> paramsClass) {
        return new RequestFactory<P>(paramsClass);
    }

}

我的客户端代码如下:

Request devInfoRequest = RequestFactory.createFactory(RequestType.SYSTEM_INFO.getRequestClass()).create(externalArgs);

我在订单地图请求类型中使用此ENUM:

public enum RequestType {
    SYSTEM_INFO(DeviceInfoParams.class),
    INTERFACES(InterfacesParams.class)
}

我的问题是 - 如何使用它,因为我不能将构造函数和静态构建器都添加到RequestParams接口(或抽象类)?

编辑:AdamSkywalker's answer之后): 我希望我的客户端代码是:

Request<InterfacesParams> interfacesRequest =
                RequestFactory.<InterfacesParams>createFactory(RequestType.INTERFACES.create(externalArgs)).create("get");

但它需要枚举返回函数来匹配泛型类型。

2 个答案:

答案 0 :(得分:1)

也许它并不完全是您正在寻找的东西,但您的代码过于设计。为什么不:

public enum RequestType {
    SYSTEM_INFO {
        public RequestParams create(ExternalArgs args) { return new DeviceInfoParams(args); }
    },
    INTERFACES {
        public RequestParams create(ExternalArgs args) { return new InterfacesParams(args); }
    };

    abstract RequestParams create(ExternalArgs args);
}

然后在没有反射技巧的情况下调用它:

Request req = new Request("get", singletonList(SYSTEM_INFO.create(args)));

你仍然可以使用你的工厂,但重点是消除反射的复杂性。

答案 1 :(得分:1)

正如您所观察到的,内置enum功能的问题是每个枚举值必须具有相同的类型;它们不能有不同的类型参数(事实上,枚举类甚至不接受类型参数)。

一个选项是滚动你自己的枚举 - 只需用私有构造函数和每个实例的普通静态字段写一个class RequestType<P extends RequestParam>

但是如果RequestTypeRequestFactory<...>类型真的只有你在这里显示的内容,那么通过写下来合并它们可能更有意义:

public final class RequestFactory<P extends RequestParams> {
    public static final RequestFactory<DeviceInfoParams> SYSTEM_INFO =
        new RequestFactory<>(DeviceInfoParams::new);
    public static final RequestFactory<InterfacesParams> INTERFACES =
        new RequestFactory<>(InterfacesParams::new);

    private final Function<ExternalArgs, P> mRequestParamsCreator;

    private RequestFactory(final Function<ExternalArgs, P> requestParamsCreator) {
        mRequestParamsCreator = requestParamsCreator;
    }

    public Request<P> create(final ExternalArgs externalArgs) {
        final P requestParams = mRequestParamsCreator.apply(externalArgs);
        return new Request<P>("get", Collections.singletonList(requestParams));
    }
}

(注意:上面使用了一些Java 8 / JDK 1.8功能以简洁。如果你仍然使用旧版本的Java,上面的方法仍然可以工作,但你必须写一些样板来填写差距。同样,如果DeviceInfoParamsInterfacesParams的相关构造函数声明任何已检查的异常,因为在这种情况下,它们不能隐式转换为java.util.function.Function s。)

然后,您可以通过编写(例如):

来创建请求
final Request<DeviceInfoParams> systemInfoRequest =
    RequestFactory.SYSTEM_INFO.create(externalArgs);
final Request<InterfacesParams> interfacesRequest =
    RequestFactory.INTERFACES.create(externalArgs);

与AdamSkywalker的方法一样,这完全避免了反射。