封装自己的本地缓存类(单例模式、适配器模式应用)

前言

很多小伙伴比较喜欢直接使用 localStorage 或者 sessionStorage 。虽然可以满足大多数场景,但是在特殊需求情况下就需要进行二次封装处理,例如 设置过期时间、使用其他存储方式、每次存取需要序列化与反序列化。而且有些项目体量大、产品一直迭代、维护人员和开发人员一茬接一茬的这种项目,有时在不同模块 甚至不同页面 使用的缓存都是单独封装的 或者 是’裸奔’的。为方便项目使用,特对常规操作进行封装。此篇文章会带着你从零到一的封装一个本地缓存类,从需求分析到架构设计以及部分设计模式的讲解。

脑图设计

脑图就是进行头脑风暴。将自己的碎片式的 **idea **抽象出关键点,通过关键点在去思考如何去实现以及应该怎么做。

支持多种驱动

适配器模式

有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类能在一起工作,做法是将类自己的接口包裹在一个已存在的类中。
核心: 实现了相同入参,相同返回。

例如后台小伙伴经常说的JDBC其实就是 是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。这样就可以通过同样的方法操作不同的数据库了。

驱动的接口设计

本文代码并未使用 **ts **只是我认为这样的表达可能会相对清楚一些。(挖个坑 写一个后面使用 ts 重写这个小工具,然后发布为npm包的教程)

/** 接口设计 */
interface ZStorageInterface {
  /**
   * 驱动名字
   */
  name: string;
  /**
   * getÏ
   * 通过key获取值
   */
  get: (key: string) => string;
  /**
   * set
   * 通过key设置值
   */
  set: (key: string, value: string) => void;
  /**
   * remove
   * 通过key删除值
   */
  remove: (key: string) => void;
  /**
   * clear
   * 清除全部
   */
  clear: () => void;
  /**
   * hasKey
   * 判断key 是否存在
   */
  hasKey: (key: string) => boolean;
}

实现LocalStorage驱动

export default {
  name: "localStorage",
  get: (key) => window.localStorage.getItem(key),
  set: (key, value) => window.localStorage.setItem(key, value),
  remove: (key) => window.localStorage.removeItem(key),
  clear: () => window.localStorage.clear(),
  hasKey: (key) => window.localStorage.hasOwnProperty(key),
};

实现过期时间

定义存储数据格式

存储数据格式伪代码
const payload = {
  value: value,
  time: Date.now(),
  expire: expire,
};

校验是payload是否过期伪代码

  const checkExpire = (payload) =>
    payload.expire &&
    payload.expire != -1 &&
    payload.expire < (Date.now() - payload.time) / 1000;

实现存值

ZStorage 核心类实现

/** 驱动器引入 */
import driverMap from "./drivers/index.js";
const defaultOptions = {
  /**  sessionStorage localStorage  cookie 及 custom 自定义存储  */
  driver: "localStorage",
  /** key前缀 */
  prefix: "test_",
  /** 编码类型 */
  charset: "utf-8",
};

class ZStorage {
  constructor(options) {
    this.options = { ...defaultOptions, ...options };
    this._driverInit();
  }
  /** 驱动初始化 */
  _driverInit() {
    const driver = this.options.driver;
    if (Object.keys(driverMap).includes(driver)) {
      this._store = driverMap[driver];
    } else if (driver == "custom") {
      this._store = this.options.customDriver;
    } else {
      throw new Error("驱动器不存在");
    }
  }
  /**
   * 获取驱动器
   * @deprecated (废弃)
   * @returns
   */
  getDriver() {
    return this._store;
  }
  /**
   * 获取前缀
   */
  getPrefix() {
    return this.options.prefix;
  }
  /**
   * 自动添加前缀
   * @param {*} key
   * @returns
   */
  _autoAddPrefix(key) {
    return this.options.prefix + key;
  }
  /**
   * 校验是否过期
   */
  _checkExpire = (payload) =>
    payload.expire &&
    payload.expire != -1 &&
    payload.expire < (Date.now() - payload.time) / 1000;
  /**
   * 设置值
   * @param {*} key
   * @param {*} value
   */
  set(key, value, expire = -1) {
    const payload = {
      value: value,
      time: Date.now(),
      expire: expire,
    };
    this._store.set(this._autoAddPrefix(key), JSON.stringify(payload));
  }
  /**
   * 获取值
   * @param {*} key
   * @param {*} defaultValue
   * @returns
   */
  get(key, defaultValue = undefined) {
    if (!this.hasKey(key)) return defaultValue;
    const data = JSON.parse(this._store.get(this._autoAddPrefix(key)));
    if (checkExpire(data)) {
      this.remove(key);
      return defaultValue;
    }
    return data.value;
  }
  /**
   * 删除key
   * @param {*} key
   */
  remove(key) {
    this._store.remove(this._autoAddPrefix(key));
  }
  /**
   * 清空
   */
  clear() {
    this._store.clear();
  }
  /**
   * 是否存在key
   * @param {*} key
   * @returns
   */
  hasKey(key) {
    return this._store.hasKey(this._autoAddPrefix(key));
  }
}

驱动器

sessionStorage

export default {
  name: "sessionStorage",
  get: (key) => window.localStorage.getItem(key),
  set: (key, value) => window.localStorage.setItem(key, value),
  remove: (key) => window.localStorage.removeItem(key),
  clear: () => window.localStorage.clear(),
  hasKey: (key) => window.localStorage.hasOwnProperty(key),
};

localStorage

export default {
  name: "localStorage",
  get: (key) => window.localStorage.getItem(key),
  set: (key, value) => window.localStorage.setItem(key, value),
  remove: (key) => window.localStorage.removeItem(key),
  clear: () => window.localStorage.clear(),
  hasKey: (key) => window.localStorage.hasOwnProperty(key),
};

cookie

import Cookies from "js-cookie";
export default {
  name: "cookie",
  get: Cookies.get,
  set: Cookies.set,
  remove: (key) => Cookies.remove(key, { path: "" }),
  clear: () => {
    document.cookie = "";
  },
  hasKey: (key) => Cookies.get().hasOwnProperty(key),
};

CustomDriver 实现定制化驱动

class CustomDriver {
  data = {};
  name = "CustomDriver";
  get(key) {
    return this.data[key];
  }
  set(key, value) {
    this.data[key] = value;
  }
  remove(key) {
    delete this.data[key];
  }
  clear() {
    this.data = {};
  }
  hasKey(key) {
    return this.data.hasOwnProperty(key);
  }
}
测试
const s = new ZStorage({
  driver: "custom",
  customDriver: new CustomDriver(),
});

s.set("key", "我是测试数据", 1);
console.log(s.get("key")); // 我是测试数据

setTimeout(() => {
  console.log(s.get("key")); // 我是测试数据
}, 800);

setTimeout(() => {
  console.log(s.get("key")); // undefined
}, 1000);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵忠洋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值