2

java.sql.ResultSet(値の読み取り用)およびjava.sql.PreparedStatement(値の書き込み用)と同様のインターフェースを提供するサードパーティの RPC-API があります。次のようになっているとします。

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

汎用ラッパーにゲッターを実装するにはどうすればよいですか? 同様のシナリオを詳細に説明するこの回答を見つけましたが、これを私の問題に移すことはできません。具体的には、これを書くとき:

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

にキャストできないというコンパイラ エラーが表示されますがParameterizedType、その理由がわかりません。誰もこれを達成する方法を説明できますか?

4

2 に答える 2

2

私はこれについてかなり長い間考え、最終的に別のアプローチを思いつきました:

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 の回答と簡単に比較してみましょう。

不利益:

  • 提供するすべてのデータ型に対して新しいクラスを作成する必要があります

アドバンテージ:

  • ファクトリの static ブロックに 1 行追加するだけで済み、RemoteVariable の getter と setter に 2 つの新しい if ブロックを追加する必要はありません。
  • get と set は、毎回 if-else-blocks を処理する必要はありません
于 2013-06-27T07:55:33.987 に答える