Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

系统设计题:缓存类 TipCache设计 #511

Open
Sunny-117 opened this issue Aug 14, 2024 · 1 comment
Open

系统设计题:缓存类 TipCache设计 #511

Sunny-117 opened this issue Aug 14, 2024 · 1 comment

Comments

@Sunny-117
Copy link
Owner

假设你有一个缓存类 TipCache,用于在内存中存储键值对。以下是该类的初始实现:

class TipCache {
    constructor() {
        this._cachePool = {};
    }
    
    set(key, value) {
        this._cachePool[key] = value;
    }
    
    get(key) {
        return this._cachePool[key];
    }
}

export default new TipCache();

任务1:基于上述 TipCache 类,请你完成以下功能:

  • 实现一个 delete 方法,能够根据键删除缓存中的数据。
  • 实现一个 has 方法,检查缓存中是否存在某个键。

任务2:为该缓存类增加以下高级功能:

  • 自动过期机制:增加缓存项的过期时间参数,支持在设置缓存项时传入一个过期时间(以毫秒为单位)。如果缓存项过期,get 方法应该返回 null 或 undefined。
  • LRU (Least Recently Used) 淘汰策略:为 TipCache 类添加 LRU 淘汰策略。在缓存空间满时,删除最久未使用的缓存项。你需要增加一个容量限制参数 maxSize,当缓存数量超过 maxSize 时,自动淘汰最近最少使用的缓存项。

任务3:编写单元测试,确保你的实现能够正确处理以下情况:

  • 正常的 set 和 get 操作。
  • 删除缓存项。
  • 检查缓存项是否存在。
  • 自动过期的缓存项。
  • 当缓存满时,LRU 策略正确执行。

要求:

  • 请使用原生 JavaScript 实现,不依赖第三方库。
  • 代码需具备良好的可读性,并提供必要的注释说明。
  • 所有代码需经过充分的单元测试,并保证通过。

提示

  • 考虑使用 Map 来实现 LRU 淘汰策略。
  • 过期机制可以通过 setTimeout 或存储时间戳来实现。
@Sunny-117
Copy link
Owner Author

class TipCache {
    constructor(maxSize = 5) {
        this._cachePool = new Map(); // 使用 Map 来维护顺序
        this._maxSize = maxSize;
    }

    _isExpired(entry) {
        if (entry.expiry && Date.now() > entry.expiry) {
            return true;
        }
        return false;
    }

    set(key, value, ttl = 0) {
        if (this._cachePool.has(key)) {
            // 删除旧的位置,重新插入新位置
            this._cachePool.delete(key);
        } else if (this._cachePool.size >= this._maxSize) {
            // 淘汰最久未使用的缓存项
            const oldestKey = this._cachePool.keys().next().value;
            this._cachePool.delete(oldestKey);
        }

        const expiry = ttl > 0 ? Date.now() + ttl : null;
        this._cachePool.set(key, { value, expiry });
    }

    get(key) {
        if (!this._cachePool.has(key)) {
            return null;
        }

        const entry = this._cachePool.get(key);
        if (this._isExpired(entry)) {
            // 过期处理
            this._cachePool.delete(key);
            return null;
        }

        // 每次访问都将缓存项移动到 Map 的尾部
        this._cachePool.delete(key);
        this._cachePool.set(key, entry);

        return entry.value;
    }

    delete(key) {
        return this._cachePool.delete(key);
    }

    has(key) {
        if (!this._cachePool.has(key)) {
            return false;
        }

        const entry = this._cachePool.get(key);
        if (this._isExpired(entry)) {
            // 过期处理
            this._cachePool.delete(key);
            return false;
        }

        return true;
    }

    size() {
        return this._cachePool.size;
    }
}

export default TipCache;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant