如何为类似ResultSet的API实现通用包装器?

时间:2013-06-26 10:14:08

标签: java generics reflection

我有一个第三方RPC-API,提供类似于java.sql.ResultSet(用于读取值)和java.sql.PreparedStatement(用于写入值)的接口。假设它看起来像这样:

public interface RemoteDeviceProxy {
    public void setBoolean(Boolean value);
    public void setInteger(Integer value);
    // ...

    public Boolean getBoolean();
    public Integer getInteger();
    // ...
}

我想为这个API编写一个包装器,它使用泛型来创建特定类型的实例:

public class <T> RemoteVariable {
    private final RemoteDeviceProxy wrappedDevice;

    public RemoteVariable(RemoteDeviceProxy wrappedDevice) {
        this.wrappedDevice = wrappedDevice;
    }

    public T get() {
        // should call wrappedDevice.getBoolean() if T is Boolean, etc.
        // how to implement?
    }

    public void set(T newValue) {
        // should call wrappedDevice.setBoolean(newValue) if T is Boolean, etc.
        // implement using instanceof
    }
}

如何在通用包装器中实现getter?我发现this answer深入解释了类似的情况,但我无法将其转移到我的问题中。具体来说,当我写这篇文章时:

public T get() {
        Type[] actualTypeArguments = ((ParameterizedType) getClass())
                                         .getActualTypeArguments();
    }

我收到编译错误,说我无法转发ParameterizedType,我不明白为什么。任何人都可以解释如何实现这个目标吗?

2 个答案:

答案 0 :(得分:2)

这是一种方式:

public class <T> RemoteVariable {
    private final RemoteDeviceProxy wrappedDevice;
    private final Class<T> clazz;

    public RemoteVariable(RemoteDeviceProxy wrappedDevice, Class<T> clazz) {
        this.wrappedDevice = wrappedDevice;
        this.clazz = clazz;
    }

    public T get() {
        if(clazz == Boolean.class){return clazz.cast(wrappedDevice.getBoolean());}
        else if(clazz == Integer.class){return clazz.cast(wrappedDevice.getInteger());}
        // ...
    }

    // ...
}

答案 1 :(得分:2)

我想了很长一段时间,最后想出了一个不同的方法:

首先我向你添加了一个getter RemoteVariable类:

protected RemoteDeviceProxy getWrappedProxy() {
    return wrappedProxy;
}

其次,我创建了一个将在以后由工厂使用的构建器界面:

public interface RemoteVariableBuilder {
    public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy);
}

然后我为Boolean ...

创建了非泛型子类
public class RemoteBooleanVariable extends RemoteVariable<Boolean> implements RemoteVariableBuilder {

    public RemoteBooleanVariable(RemoteDeviceProxy wrappedProxy) {
        super(wrappedProxy);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
        return (RemoteVariable<T>) new RemoteBooleanVariable(wrappedProxy);
    }

    @Override
    public Boolean get() {
        return getWrappedProxy().getBoolean();
    }

    @Override
    public void set(Boolean value) {
        getWrappedProxy().setBoolean(value);
    }

}

......和整数......

public class RemoteIntegerBuilder extends RemoteVariable<Integer> implements RemoteVariableBuilder {

    public RemoteIntegerBuilder(RemoteDeviceProxy wrappedProxy) {
        super(wrappedProxy);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
        return (RemoteVariable<T>) new RemoteIntegerBuilder(wrappedProxy);
    }

    @Override
    public Integer get() {
        return getWrappedProxy().getInteger();
    }

    @Override
    public void set(Integer value) {
        getWrappedProxy().setInteger(value);
    }

}
实际上,eclipse在知道基类和接口后创建了大部分代码。

最后一步是创建一个工厂

public class RemoteVariableFactory {
    private static final Map<String, RemoteVariableBuilder> BUILDERS = new HashMap<>();

    static {
        BUILDERS.put(Boolean.class.getName(), new RemoteBooleanVariable(null));
        BUILDERS.put(Integer.class.getName(), new RemoteIntegerBuilder(null));
        // add more builders here
    }

    public static <T> RemoteVariable<T> getRemoteVariable(RemoteDeviceProxy wrappedProxy, Class<T> typeClass) {
        RemoteVariableBuilder remoteVariableBuilder = BUILDERS.get(typeClass.getName());

        if (remoteVariableBuilder == null) {
            return null; // or throw an exception whichever is better in your case 
        }
        return remoteVariableBuilder.buildNewVariable(wrappedProxy);
    }
}

现在我们准备创建新的RemoteVariables ......

RemoteVariable<Boolean> var1 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Boolean.class);
RemoteVariable<Integer> var2 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Integer.class);

总结一下,让我们快速比较一下Eng.Fouad的答案:

缺点:

  • 您需要为您提供的每种数据类型创建一个新类

优势:

  • 你只需要在工厂的静态块中添加一行,而不是在RemoteVariable的getter和setter中添加两个新的if
  • 获取并设置不必每次都通过if-else-blocks