【发布时间】:2013-05-04 21:27:52
【问题描述】:
我有一个接口,Resource,它应该包装 something 并在被包装的对象上公开一些操作。
我的第一个方法是编写以下内容,同时牢记 Strategy 模式。
interface Resource<T> {
ResourceState read();
void write(ResourceState);
}
abstract class AbstractResource<T> implements Resource<T> {
// This is where the Strategy comes in.
protected AbstractResource(ResourceStrategy<T> strat) {
// ...
}
// Both the read and write implementations delegate to the strategy.
}
class ExclusiveResource<T> extends AbstractResource<T> { ... }
class ShareableResource<T> extends AbstractResource<T> { ... }
上述两种实现在使用的锁定方案上有所不同(常规锁或读写锁)。
还有一个ResourceManager,一个负责管理这些事情的实体。
我对客户使用的想法是:
ResourceManager rm = ...
MyCustomObject o = ...
MyCustomReadWriteStrategy strat = ...
rm.newResourceFor(o, "id", strat);
这样,客户端会知道资源,但不必直接处理资源(因此是包私有类)。另外,我可以自己实现一些公共资源,比如套接字,而客户端只会要求它们(ie,我必须写一个SocketStrategy implements ResourceStrategy<Socket>)。
ResourceManager rm = ...
rm.newSocketResource("id", host, port);
要访问资源,他会向经理请求处理程序。这是由于每个线程都有一些特定的访问权限,因此管理器会创建一个具有适当访问权限的处理程序。
// This is in the ResourceManager class.
public ResourceHandler getHandlerFor(String id) {
if (!canThreadUseThisResource(id)) throw ...;
if (isThreadReaderOnly()) {
return new ResourceReadHandler( ... );
} else {
return new ResourceWriteHandler( ... );
}
}
这就是问题所在。
这种方法对我来说似乎干净和清晰,它对用户来说似乎也很直观。
但是,正如暗示的那样,管理器保留了从标识符到资源的映射。这将如何声明,以及管理器如何从地图中检索资源?
Map<String, Resource<?>> map;
// Can I go around without any specific cast? Not sure yet.
Resource<?> r = map.get(id);
// This could have an enum ResourceType, to check if thread has privileges
// for the specific type.
这种设计是否可以接受和/或遵循良好做法?
或者,我可以清除泛型,让 ExclusiveResource 和 ShareableResource 抽象和公开。
然后,这些类将由我和客户针对所需的每种类型的资源(FileResource extends ExclusiveResource、SocketResource extends ExclusiveResource、...)进行扩展。
这可能会消除对策略模式的需求,但会将我的包更多地暴露给用户。
这些替代方案中哪一个是最正确的,或被广泛接受为良好做法?
编辑:经过一番思考,我认为我可以从Resource 接口中删除泛型,因为这是造成问题的原因,并将其保留在AbstractResource 及其子类中.后者仍然可以让我对所使用的策略进行编译时验证。
public <T> void newExclusiveResourceFor(
T obj, String id, ResourceStrategy<T> strat) {
ExclusiveResource<T> r = new ExclusiveResource<>(obj, strat);
map.put(id, r);
}
不过,遵循继承的方式似乎更正确。
【问题讨论】:
-
投反对票有什么特别的原因吗?让我知道这个问题是否可以改进。
-
Resource> 带走了泛型的好处。它可以容纳任何东西。在我看来,你可以在这里消灭泛型。
-
@dkaustubh 我明白你的意思,我同意。这里的泛型只是一种确保用户定义的资源接收适当策略的方法,因为用户不能直接访问资源。但我想按照继承方式,我可以实现相同的目标,同时使用适当的工具。
-
我对@987654336@ 泛型声明感到有些困惑,因为它的成员都没有使用
T- 该接口是否有充分的理由成为泛型? -
@PaulBellora 事实上,我认为没有,正如我刚才在问题更新中指出的那样。最好将泛型从接口中取出,即使它保留在实现中。
标签: java generics inheritance architecture