我有一个建造者模式,在其中我从客户那里获取一些参数,根据这些参数构建我的建造者类,然后将该建造者类传递给我们的基础库,然后我的库将使用它。
public final class KeyHolder {
private final String clientId;
private final String deviceId;
private final int processId;
private final Cache<String, List<Response>> userCache;
private static final long MAXIMUM_CACHE_SIZE = 5000000;
private static final long EXPIRE_AFTER_WRITE = 120; // this is in seconds
private KeyHolder(Builder builder) {
this.clientId = builder.clientId;
this.deviceId = builder.deviceId;
this.processId = builder.processId;
this.maximumCacheSize = builder.maximumCacheSize;
this.expireAfterWrite = builder.expireAfterWrite;
// how to execute this line only once
this.userCache =
CacheBuilder
.newBuilder()
.maximumSize(maximumCacheSize)
.expireAfterWrite(expireAfterWrite, TimeUnit.SECONDS)
.removalListener(
RemovalListeners.asynchronous(new CustomListener(),
Executors.newSingleThreadScheduledExecutor())).build();
}
public static class Builder {
protected final int processId;
protected String clientId = null;
protected String deviceId = null;
protected long maximumCacheSize = MAXIMUM_CACHE_SIZE;
protected long expireAfterWrite = EXPIRE_AFTER_WRITE;
public Builder(int processId) {
this.processId = processId;
}
public Builder setClientId(String clientId) {
this.clientId = clientId;
return this;
}
public Builder setDeviceId(String deviceId) {
this.deviceId = deviceId;
return this;
}
public Builder setMaximumCacheSize(long size) {
this.maximumCacheSize = size;
return this;
}
public Builder setExpiryTimeAfterWrite(long duration) {
this.expireAfterWrite = duration;
return this;
}
public KeyHolder build() {
return new KeyHolder(this);
}
}
// getters here
}
每次调用我们的库时,他们都会创建一个新的 KeyHolder
构建器类,并将其传递给我们的库。每次调用时,processId
、clientId
、deviceId
都会更改,但是 maximumCacheSize
和 expireAfterWrite
将会保持不变。如上所述,我在这里使用了 guava 缓存,但由于他们每次都创建 KeyHolder
构建器类,我该如何确保以下行仅在我的构造函数中执行一次?
this.userCache =
CacheBuilder
.newBuilder()
.maximumSize(maximumCacheSize)
.expireAfterWrite(expireAfterWrite, TimeUnit.SECONDS)
.removalListener(
RemovalListeners.asynchronous(new CustomListener(),
Executors.newSingleThreadScheduledExecutor())).build();
由于当前代码,每次调用都会执行,我的库中将获得一个新的Guava缓存,因此之前使用此Guava缓存在我的库中缓存的任何条目都将丢失。
如何仅初始化特定变量一次,并在此后忽略传递给它的任何值?
更新:
public class DataClient implements Client {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
// for synchronous call
@Override
public List<Response> executeSync(KeyHolder key) {
Cache<String, List<Response>> userCache = key.getUserCache();
List<Response> response = userCache.getIfPresent(key.getUUID());
if (CollectionUtils.isNotEmpty(response)) {
return response;
}
// if not in cache, then normally call the flow and populate the cache
List<Response> dataResponse = null;
Future<List<Response>> future = null;
try {
future = executeAsync(key);
dataResponse = future.get(key.getTimeout(), TimeUnit.MILLISECONDS);
userCache.put(key.getUUID(), dataResponse);
} catch (TimeoutException ex) {
// log error and return DataResponse
} catch (Exception ex) {
// log error and return DataResponse
}
return dataResponse;
}
}
KeyHolder
类,并通过传递此类来调用我们的库。现在我的库使用此构建器类,并根据传递的参数执行额外的操作。我已编辑我的问题以更清楚地阐明这一点。现在由于我在这里使用 guava 缓存,我想根据客户端传递的值初始化我的 guava 缓存,但我只想初始化一次。然后我在我的库中使用此 guava 缓存,如上面的代码所示。 - johnuserCache
是基于实例的和 final 的,因此他可以创建该类的多个对象,并且每个对象都有不同的userCache
,它们不是共享的。现在为了纠正这个问题,他可以使用 enum/使变量 static/使用专用类或工厂,这些都是实现细节。在我看来,需要改动最少的是“static”方法,但是否在这种情况下是理想的则有争议。 - boxed__lstatic
会加剧问题。KeyHolder
没有理由与响应缓存耦合在一起。它仅被耦合在一起,以便人们可以通过KeyHolder
指定缓存设置,这是不合逻辑的并且创建了紧密的耦合。 - Dioxin