如何使用guava class在接口中实例映射?
How to use guava class to instance map in interface?
我有一个名为 RestClientInterface 的接口,它由抽象 RestClient class 实现,那些 class 由 SearchRestClient 和 IndexRestClient 扩展。这两个 classes 都是单例。我希望能够在接口静态方法getInstance 中实现。我决定像这里建议的那样使用 Guava 库:How can I implement abstract static methods in Java?.
我在接口中实现了两个静态方法:
public interface RestClientInterface {
ClassToInstanceMap<RestClientInterface> classToInstanceMap = MutableClassToInstanceMap.create();
static <T extends RestClientInterface> T getInstance(Class<T> type) {
return classToInstanceMap.getInstance(type);
}
static <T extends RestClientInterface> void registerInstance(Class<T> type, T identity) {
classToInstanceMap.putIfAbsent(type, identity);
}
}
和下一个注册的实例都扩展 classes:
public class IndexRestClient extends RestClient {
static {
RestClientInterface.registerInstance(IndexRestClient.class, getInstance());
}
/**
* IndexRestClient singleton.
*/
private static IndexRestClient instance = null;
private IndexRestClient() {}
/**
* Return singleton variable of type IndexRestClient.
*
* @return unique instance of IndexRestClient
*/
private static IndexRestClient getInstance() {
if (Objects.equals(instance, null)) {
synchronized (IndexRestClient.class) {
if (Objects.equals(instance, null)) {
instance = new IndexRestClient();
instance.initiateClient();
}
}
}
return instance;
}
}
接下来我这样称呼它:
IndexRestClient restClient = RestClientInterface.getInstance(IndexRestClient.class);
但每次我得到的都是空值。实例的静态注册不起作用,因为已注册实例的数组为空。我怎样才能正确实例化这两个 classes?
那是因为classToInstanceMap
对象不是静态的,而你使用的方法是静态的。这意味着仅当您创建 class 的新实例时才会创建地图。只需将静态关键字添加到此对象即可。
经过我们的讨论,问题可能与 class IndexRestClient
的延迟加载有关,如果它在进一步使用之前仅在语句 RestClientInterface.getInstance(IndexRestClient.class)
中被引用,因为我是不确定对 IndexRestClient.class
的引用是否足以触发 class.
的 load/initialization
假设这里的问题确实是 class IndexRestClient
被延迟加载,你需要反转注册逻辑的控制,即而不是IndexRestClient
在注册表中注册自己,中间有一个“Registrar
”来处理它。
但是在我看来,你的 RestClientInterface
的合同应该改变,因为它不知道你的 Rest 客户的具体类型,而我知道你想隐藏他们创建的实现。
您可能想看看 Java service loader 机制,它看起来很接近您想要做的事情,例如:
public final RestClients {
private final ServiceLoader<RestClient> restClients = ServiceLoader.load(RestClient.class);
public RestClient getClient(RestClientSpec spec) throws NoClientFoundForSpecException {
for (RestClient client : restClients) {
if (/* client matches your specification */) {
return client;
}
}
throw new NoClientFoundForSpecException(spec);
}
}
Service Loader 模式可能提供比您实际想要的更多的封装和隐藏更多的实现(因为您显然使用的是具体类型),但我觉得它值得一提。
我有一个名为 RestClientInterface 的接口,它由抽象 RestClient class 实现,那些 class 由 SearchRestClient 和 IndexRestClient 扩展。这两个 classes 都是单例。我希望能够在接口静态方法getInstance 中实现。我决定像这里建议的那样使用 Guava 库:How can I implement abstract static methods in Java?.
我在接口中实现了两个静态方法:
public interface RestClientInterface {
ClassToInstanceMap<RestClientInterface> classToInstanceMap = MutableClassToInstanceMap.create();
static <T extends RestClientInterface> T getInstance(Class<T> type) {
return classToInstanceMap.getInstance(type);
}
static <T extends RestClientInterface> void registerInstance(Class<T> type, T identity) {
classToInstanceMap.putIfAbsent(type, identity);
}
}
和下一个注册的实例都扩展 classes:
public class IndexRestClient extends RestClient {
static {
RestClientInterface.registerInstance(IndexRestClient.class, getInstance());
}
/**
* IndexRestClient singleton.
*/
private static IndexRestClient instance = null;
private IndexRestClient() {}
/**
* Return singleton variable of type IndexRestClient.
*
* @return unique instance of IndexRestClient
*/
private static IndexRestClient getInstance() {
if (Objects.equals(instance, null)) {
synchronized (IndexRestClient.class) {
if (Objects.equals(instance, null)) {
instance = new IndexRestClient();
instance.initiateClient();
}
}
}
return instance;
}
}
接下来我这样称呼它:
IndexRestClient restClient = RestClientInterface.getInstance(IndexRestClient.class);
但每次我得到的都是空值。实例的静态注册不起作用,因为已注册实例的数组为空。我怎样才能正确实例化这两个 classes?
那是因为classToInstanceMap
对象不是静态的,而你使用的方法是静态的。这意味着仅当您创建 class 的新实例时才会创建地图。只需将静态关键字添加到此对象即可。
经过我们的讨论,问题可能与 class IndexRestClient
的延迟加载有关,如果它在进一步使用之前仅在语句 RestClientInterface.getInstance(IndexRestClient.class)
中被引用,因为我是不确定对 IndexRestClient.class
的引用是否足以触发 class.
假设这里的问题确实是 class IndexRestClient
被延迟加载,你需要反转注册逻辑的控制,即而不是IndexRestClient
在注册表中注册自己,中间有一个“Registrar
”来处理它。
但是在我看来,你的 RestClientInterface
的合同应该改变,因为它不知道你的 Rest 客户的具体类型,而我知道你想隐藏他们创建的实现。
您可能想看看 Java service loader 机制,它看起来很接近您想要做的事情,例如:
public final RestClients {
private final ServiceLoader<RestClient> restClients = ServiceLoader.load(RestClient.class);
public RestClient getClient(RestClientSpec spec) throws NoClientFoundForSpecException {
for (RestClient client : restClients) {
if (/* client matches your specification */) {
return client;
}
}
throw new NoClientFoundForSpecException(spec);
}
}
Service Loader 模式可能提供比您实际想要的更多的封装和隐藏更多的实现(因为您显然使用的是具体类型),但我觉得它值得一提。