在java中输出类型不同时的工厂模式

时间:2017-02-14 07:49:23

标签: java design-patterns factory

我对java很新,下面是我的mapper接口定义:

public interface CourseMapper {
    Course map(JsonObject courseJson);
    List<Course> map(JsonArray coursesJson);
}

public interface LocationMapper {
    Location map(JsonObject locationJson);
    List<Location> map(JsonArray locationsJson);
}

以下是两个类:

public interface Location {
    Long id();
    String name();
    Location mutate(Long id);
}

public interface Course {
    Long id();
    String name();
    Course mutate(Long id);
}

我需要的是基于密钥(String),我需要调用相应map()的相应Mapper函数。示例如果key=="location",我需要调用LocationMapper,如果是key=="course",我需要调用CourseMapper(对于gson Mapper)......等等

我尝试使用Factory Pattern,但是当输出属于不同类型时,似乎同样不起作用。有没有人知道如何实现同样的目标而不会过分复杂化if-else阶梯。

1 个答案:

答案 0 :(得分:3)

最简单的方法是使用Map<String, Object>将地图集存储在:

private Map<String, Object> mappers;

public <T> T getMapper(String key, Class<T> mapperType) {
    Object mapper = mappers.get(key);
    // code for when mapper == null
    if (mapperType.isAssignableFrom(mapper)) {
        return (T) mapper;
    } else {
         // code for when mapper is of wrong type
    }
}

然而,正如您所注意到的,这会放弃静态类型检查,因此只能在运行时找到任何类型不匹配。

更复杂的方法可以保存(排序)静态类型检查。它基本上将结果类型与字符串键绑定:

private static class MapperKey<T> {
    private final String key;

    public MapperKey(String key) {
        this.key = key;
    }
}

private Map<String, Object> mappers;

public static final MapperKey<CourseMapper> COURSE_KEY = new MapperKey<CourseMapper>("course");

public <T> void addMapper(MapperKey<T> mapperKey, T mapper) {
    mappers.put(mapperKey.key, mapper);
}

public <T> T getMapper(MapperKey<T> mapperKey) {
    Object mapper = mappers.get(mapperKey.key);
    // code for when mapper == null
    return (T) mapper;
}

然而,这种方法取决于用户使用MapperKey的预定义常量,或者创建正确的密钥(相应密钥的正确类型参数)。

最后,如果您可以用此替换CourseMapperLocationMapper接口:

public interface Mapper<T> {
    T map(JsonObject courseJson);
    List<T> map(JsonArray coursesJson);
}

如果每个输出类型只需要一个映射器,则可以使用输出类型作为键:

private Map<Class<?>, Mapper<?>> mappers;

public <T> void addMapper(Class<T> outputType, Mapper<T> mapper) {
    mappers.put(outputType, mapper);
}

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> outputType) {
    return (T) mappers.get(outputType);
}