Stories

Detail Return Return

開竅了!如何為緩存工具類(CacheUtil中的static方法)定義interface(上) - Stories Detail

兩個不同策略的緩存工具類

在我們系統的基建包裏,有一個基於redis的get/set等基礎api封裝的 CacheUtil
CacheUtil 主要有下面2個靜態方法:

import java.util.function.Supplier;

public class CacheUtil {
    /**
     * 獲取緩存。如果沒有,則設置
     */
    public static <T> T getCache(String key, long seconds, Supplier<T> supplier) {
        return getCache(key, seconds, false, supplier);
    }

    /**
     * 獲取緩存。如果沒有,則設置
     */
    public static <T> T getCache(String key, long seconds, boolean cacheNull, Supplier<T> supplier) {
        Object obj = redisUtil.get(key); // 這裏的RedisUtil類封裝了 redis 的get/set等基礎操作
        if (null == obj) {
            T value = supplier.get();
            ......
            redisUtil.set(key, value, seconds);
            return value;
        } else {
        	......
            return (T) obj;
        }
    }
}

隨着後續系統迭代過程中,我增加了一個基於本地緩存框架 hutool-cache 的 LFUCache、TimedCache 來實現的 LocalCacheUtil
CacheUtil 一樣的是,LocalCacheUtil 中也主要有下面2個靜態方法:

import java.util.function.Supplier;

public class CacheUtil {
    /**
     * 獲取緩存。如果沒有,則設置
     */
    public static <T> T getCache(String key, long seconds, Supplier<T> supplier) {
        return getCache(key, seconds, false, supplier);
    }

    /**
     * 獲取緩存。如果沒有,則設置
     */
    public static <T> T getCache(String key, long seconds, boolean allowCacheNullOrEmpty, Supplier<T> supplier) {
        return getCache(timedCache, key, seconds, allowCacheNullOrEmpty, supplier);
    }

    private static <T> T getCache(Cache<String, Object> myCache, String key, Long seconds, boolean allowCacheNullOrEmpty, Supplier<T> supplier) {
        Object cachedValue = myCache.get(key, false);
        if (cachedValue != null) {
            return (T) cachedValue;
        }
        // 允許緩存null值的情況下,如果存在緩存,則直接返回
        if (allowCacheNullOrEmpty && myCache.containsKey(key)) {
            return (T) myCache.get(key, false);
        }

        ......
        T result = supplier.get();
        if (seconds == null) {
            myCache.put(key, result);
        } else {
            myCache.put(key, result, TimeUnit.SECONDS.toMillis(seconds));
        }
        return result;
    }
}

如何為兩個緩存工具類抽取公共能力?

翻閲 git 提交記錄,我發現 CacheUtil 是2020-09 創建的,LocalCacheUtil 是 2022-12 創建的。
雖然兩年多過去了,但這其中有一個困擾着我的程序設計問題並沒有被遺忘。

這個程序設計問題是, CacheUtilLocalCacheUtil 的職責是相同的,兩者都是用來緩存數據。那麼,如果能夠為兩者抽象出來一個緩存數據的 interface,該多香啊!

可是, getCache 方法是 static 靜態方法。我們知道,靜態方法是無法實現接口的

我總不能把 getCache 方法改為非靜態方法吧?

我不能。倒不是因為需要改所有的調用代碼,而是在程序設計原則中,工具類的設計理念通常是為了提供一組相關的實用方法,這些方法不依賴於類的實例狀態,而是專注於執行特定的功能。代碼實現中,我們通常將工具類的方法定義為 static 或者通過其他方式(如私有化構造函數)防止類在外部被實例化

那麼,我沒有辦法了!

我曾經在遙遠的2017年聽過一個架構師講過類似場景的解決方案,可惜的是,忘卻了,腦子裏只留下“講解過”這三個字了。

直到最近,我才想到方案。(>>點擊下一篇查看)

user avatar dennyLee2025 Avatar yangjiaobaoza Avatar codejourney-blog Avatar
Favorites 3 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.