数据访问对象模式

数据访问对象模式

数据访问对象模式Data Access Object PatternDAO模式,用于把低级的数据访问API或操作从高级的业务服务中分离出来,准确来说数据访问对象模式不属于通常定义的设计模式范畴,但数据访问对象模式是一种非常有用的数据访问管理构建技巧。

描述

数据访问对象模式就是对数据源的访问与存储进行封装,提供一个数据访问对象类负责对存储的数据进行管理和操作,规范数据存储格式,类似于后台的DAO层。
HTML5提供了两种在客户端存储数据的新方法: localStoragesessionStorage,他们是Web Storage API提供的两种存储机制,区别在于前者属于永久性存储,而后者是局限于当前会话以及衍生窗口的数据传递。由于WebStorage采用Key-Value的方式存取数据,而且只能存字符串(任何类型存储的时候都会被转为字符串,读取的时候需要进行类型转换),所以我们可以对Key的格式进行规范,比如模块名+Key,开发人员+Key等,还可以在值中添加一段前缀用来描述数据,如添加数据过期日期的时间戳,用来管理数据的生命周期。具体格式项目组可以自己定义,主要是便于管理,防止出现冲突,在前端方面其实主要是对于本地存储进行了一次封装,用以进行一个规范性约束,约定好规范后就可以开始定义数据访问对象了。

实现

/**
 * LocalStorage数据访问类
 * @param {string} prefix Key前缀
 * @param {string} timeSplit 时间戳与存储数据之间的分割符
 */
var DAO = function (prefix,timeSplit) {
    this.prefix = prefix;
    this.timeSplit = timeSplit || "|-|";
}

// 原型方法
DAO.prototype = {
    constructor: DAO,// 操作状态
    status: {
        SUCCESS: 0,// 成功
        FAILURE: 1,// 失败
        OVERFLOW: 2,// 溢出
        TIMEOUT: 3      // 过期
    },// 本地存储对象
    storage: localStorage || window.localStorage,/**
     * 获取带前缀的真实键值
     * @param key 数据字段标识
     */
    getKey: function (key) {
        return this.prefix + key;
    },/**
     * 添加(修改)数据
     * @param key 数据字段标识
     * @param value 数据值
     * @param callback 回调函数
     * @param time 过期时间
     */
    set: function (oriKey,value,callback,time) {
        let status = this.status.SUCCESS; // 默认为成功状态
        let key = this.getKey(oriKey);
        try{
            time = new Date(time).getTime() || time.getTime(); // 获取过期时间戳
        }catch(e){
            time = new Date().getTime() + 1000 * 60 * 60 * 24 * 30; // 未设置过期时间时默认为一个月
        }
        try{
            this.storage.setItem(key,time + this.timeSplit + value); // 向本地存储中添加(修改)数据
        }catch(e){
            status = this.status.OVERFLOW; // 发生溢出
        }
        callback && callback.call(this,status,key,value); // 执行回调并传入参数
    },/**
     * 获取数据
     * @param key 数据字段标识
     * @param callback 回调函数
     */
    get: function (oriKey,callback) {
        let key = this.getKey(oriKey);
        let status = this.status.SUCCESS;    // 获取数据状态
        let value = null;    // 获取数据值
        try{
            value = this.storage.getItem(key); // 从本地存储获取数据
        }catch(e){
            status = this.status.FAILURE; // 获取数据失败
            value = null;
        }
        // 如果成功获取数据
        if (status !== this.status.FAILURE) {
            let index = value.indexOf(this.timeSplit);
            let timeSplitLen = this.timeSplit.length;
            let time = value.slice(0,index); // 获取时间戳
            // 判断数据是否未过期
            if(new Date(1 * time).getTime() > new Date().getTime() || time === 0) {
                value = value.slice(index + timeSplitLen); // 获取数据值
            }else {
                value = null; // 数据已过期,删除数据
                status = this.status.TIMEOUT;
                this.remove(key);
            }
        }
        callback && callback.call(this,value); // 执行回调
        return value; // 返回结果值
    },/**
    * 删除数据
    * @param key 数据字段标识
    * @param callback 回调函数
    */
    remove: function (oriKey,callback) {
        let status = this.status.FAILURE; // 设置默认状态为失败
        let key = this.getKey(oriKey);
        let value = null;
        try {
            value = this.storage.getItem(key); // 获取数据值
        }catch(e){
            // 数据不存在,不采取操作
        }
        if(value){ // 如果数据存在
            try{
                // 删除数据
                this.storage.removeItem(key);
                status = this.status.SUCCESS;
            }catch(e) {
                // 数据删除失败,不采取操作
            }
        }
        // 执行回调并传入参数,删除成功则传入被删除的数据值
        let param = status > 0 ? null : value.slice(value.indexOf(this.timeSplit) + this.timeSplit.length);
        callback && callback.call(this,param);
    }
};

(function(){
    let dao = new DAO("user-verify");
    dao.set("token","111",(...args) => console.log(args)); // [0,"user-verifytoken","111"]
    let value = dao.get("token","111"]
    console.log(value); // 111
    dao.remove("token","111"]
})();

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://zhuanlan.zhihu.com/p/235136284
https://zkhdev.github.io/2017/07/31/js-dao/
https://www.runoob.com/design-pattern/data-access-object-pattern.html

相关文章

什么是设计模式一套被反复使用、多数人知晓的、经过分类编目...
单一职责原则定义(Single Responsibility Principle,SRP)...
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强...
适配器模式将一个类的接口转换成客户期望的另一个接口,使得...
策略模式定义了一系列算法族,并封装在类中,它们之间可以互...
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,...