3

我以前从来没有机会使用泛型(比如编写泛型类),但现在需要出现,我遇到了一些困惑。

有这个接口,它是用来包装一些东西的。这些实现不是集合,因此,每个实例只能访问一个something

public interface Resource<T> {
    // Expected operations:
    void write(ResourceState state);
    ResourceState read();
}

作为实现,我希望有一个ExclusiveResource<T>和 至于and的执行方式,我打算使用Strategy模式。 例如,我可能有ShareableResource<T>
readwrite

// This would implement a Strategy<File>.
FileStrategy fs = new FileStrategy();
Resource<File> r = new ExclusiveResource<File>(fs);

现在,我还收集了这些资源,比如资源池。
我想将一个键映射到资源池中的每个资源,并且我想添加、检索和删除资源,但我不确定如何声明映射和方法。我尝试了以下方法:

public class ResourcePool {
    // instance variables
    private final Map<String, Resource<?>> map;

    /** Empty constructor of objects of class ResourcePool. */
    public ResourcePool() {
        map = new HashMap<String, Resource<?>>();
    }

    /** */
    public Resource<?> get(String s) {
        return map.get(s);
    }

    /** */
    public void add(String s, Resource<?> r) {
        map.put(s, r);
    }

    // ...
}

这似乎不是最合适的方法,并且引用 Josh Bloch 在Effective Java Reloaded上的话:

用户不必考虑通配符来使用您的 API。

我用以下方法测试了这段代码:

public static void test() {
    ResourcePool rp = new ResourcePool();

    Resource<String> r1 = new ShareableResource<>("test");
    Resource<Integer> r2 = new ShareableResource<>(1);
    Resource<List<String>> r3 = new ShareableResource<>(
            Arrays.asList(new String[]{"1", "2"})
    );

    // These are all ok.
    rp.add("1", r1);
    rp.add("2", r2);
    rp.add("3", r3);

    // This results in a compiler error (incompatible types).
    Resource<String> g1 = rp.get("1");

    // This results in a compiler warning (unsafe operation).
    Resource<String> g2 = (Resource<String>) rp.get("1");
}

我不喜欢它,当代码编译时出现警告。让我感到内疚,并且似乎暗示了糟糕的编码。

所以,我的问题是我应该如何处理这种情况。
这是做我想做的事情的正确方法吗?
这可以通过没有不安全操作的方式来完成吗?

4

2 回答 2

1

我认为没有任何方法可以避免使用您的设计进行未经检查的演员表。也就是说,您可以避免每次检索 a 时都必须进行强制转换Resource

@SuppressWarnings("unchecked")
public <T> Resource<T> get(String s, Class<T> c) {
    return (Resource<T>) map.get(s);
}

当您想要检索 aResource时,您可以传入所需的类,如下所示:

Resource<String> g1 = rp.get("1", String.class);

但是,您应该小心这种设计,因为没有运行时保证返回Resource的实际上是Resource<String>.

于 2013-05-04T18:23:12.540 回答
0

您可以为所需的每种类型的资源创建不同的集合,并且ResourcePool也可以通用:

ResourcePool<String> stringpool = new ResourcePool<String>();
ResourcePool<Integer> intpool = new ResourcePool<Integer>();

这将为您提供对您的类型进行编译时检查的好处。并且似乎只要从ResourcePool.

于 2013-05-04T18:38:52.000 回答