番石榴中的条件记忆

Conditional memoization in Guava

我知道如何memoize a single object。但是,我只想在满足某些条件时才记忆。我调用的服务有时 returns 响应不成功。我只想在服务响应成功时进行记忆。

MyResponse myResponse = myService.call()
boolean success = myResponse.isSuccessful();

我的缓存是这样创建的:

private Supplier<MyResponse> cache;

private void createCache() {
    this.cache = Suppliers
        .memoizeWithExpiration(myService::call, timeout,
            TimeUnit.MINUTES);
}

问题: 是否可以仅在响应成功时使用传递给 memoizeWithExpiration 方法的供应商以某种方式缓存响应?


我发现这样做的唯一解决方法是,在检索值时,先调用 cache.get(),检查缓存中存储的对象是否成功,如果不成功,则调用 createCache()再次清除它,然后再次获取值。这样,如果后续服务调用 returns 一个有效对象,它将被存储,如果不是,每个后续调用都将清除缓存并再次调用该服务。

 public MyResponse getResponse() {
    MyResponse myResponse = cache.get();
    if (myResponse.isSuccess()) {
      return myResponse;
    } else {
      createCache();
      return cache.get();
    }
  }

然而,在此解决方案中,如果缓存为空且服务 returns 未成功响应,则会立即再次调用。

您可以在服务 class 或任何其他合适的地方(这里我假设它在您的服务中)创建一个方法 callUntilSuccess。您还可以在此方法中定义最大尝试次数,之后它将 return 为空,因此您可以避免无限期地调用您的服务(此建议未在下面提供的代码中实现,但它很容易这样做)。由于 Guava 方法需要 Supplier,您甚至可以使用此逻辑创建一个 lambda 并将其直接传递给 memoizeWithExpiration 方法。

public MyResponse callUntilSuccess() {

    MyResponse response = myService.call();
    while (!response.isSuccessful()) {
        response = myService.call();
    }
    return response;
}   

然后这样memoization:

private void createCache() {
    this.cache = Suppliers
         .memoizeWithExpiration(myService::callUntilSuccess, timeout,
                TimeUnit.MINUTES);
}   

这会是您要找的吗?


    private void createCache() {
        this.cache = Suppliers.memoizeWithExpiration(
           Suppliers.compose(
               response -> (response.isSuccess() ? response : null),
               myService::call
           ),
           timeout,
           TimeUnit.MINUTES
        );
    }

这里,它会缓存响应,或者null,取决于它是否成功。

有关 compose 的更多信息,请点击此处 https://github.com/google/guava/blob/master/guava/src/com/google/common/base/Suppliers.java#L45

编辑: 如果您需要在成功时缓存值,并在失败时将缓存留空,同时 return 处理失败的请求,那么您自己就差不多了,只需稍微更改 return 中的逻辑 getResponse,像这样:


    public MyResponse getResponse() {
        final MyResponse myResponse = cache.get();
        if (!myResponse.isSuccess()) {
            this.createCache(); // clear cache
        }
        return myResponse; // don't call .get() again!
    }