JS设计模式之数据访问对象模式的实例讲解


Posted in Javascript onSeptember 30, 2017

JS设计模式之数据访问对象模式的实例讲解

引言

HTML5 提供了两种在客户端存储数据的新方法:localStorage、sessionStorage,他们是Web Storage API 提供的两种存储机制,区别在于前者属于永久性存储,而后者是局限于当前窗口的数据传递,存储在其中的数据会在当前会话结束时被删除。localStorage、sessionStorage的具体内容在这里就不多做介绍了,我们主要探讨一下在实际开发中怎样合理使用他们。

问题

大部分网站会将一些数据(如:用户Token)存储在前端,用来实现页面间的传值,对于一些大型Web应用来说,其存储的数据可能会非常多,数据的管理会变得复杂,并且一个大型项目是由多位程序员共同开发的,这时就会遇到一个问题:怎样确保自己的数据不会覆盖掉其他人的呢?因为在一个页面中大家都是使用同一个WebStorage对象,总不能把大家使用过的Key记录下来吧。这时候就可以使用数据访问对象模式来解决了。

数据访问对象模式(DAO)

数据访问对象模式就是对数据源的访问与存储进行封装,提供一个数据访问对象类负责对存储的数据进行管理和操作,规范数据存储格式,类似于后台的DAO层。

由于WebStorage采用Key-Value的方式存取数据,而且只能存字符串(任何类型存储的时候都会被转为字符串,读取的时候需要进行类型转换),所以我们可以对Key的格式进行规范,比如模块名+Key,开发人员+Key等,还可以在值中添加一段前缀用来描述数据,如添加数据过期日期的时间戳,用来管理数据的生命周期。具体格式项目组可以自己定义,主要是便于管理,防止出现冲突,约定好规范后就可以开始定义数据访问对象了。

下面以localStorage为例,介绍一下数据访问对象类的定义和使用。

代码示例

DAO类基本结构

数据访问对象类的基本结构如下,我们给键值添加了一段前缀用来避免键值冲突,并且在值中加入数据过期时间戳以及分隔符,获取值的时候再进行判断是否过期,这样可以更灵活地管理存储数据的生命周期。这里还用到了回调的方式,方便获取数据访问过程的具体结果,以及在必要时执行相关操作。

/**
 * LocalStorage数据访问类
 * @param {string} prefix Key前缀
 * @param {string} timeSplit 时间戳与存储数据之间的分割符
 */
var Dao = function (prefix, timeSplit) {
  this.prefix = prefix;
  this.timeSplit = timeSplit || '|-|';
}
// LocalStorage数据访问类原型方法
Dao.prototype = {
  // 操作状态
  status: {
    SUCCESS: 0,   // 成功
    FAILURE: 1,   // 失败
    OVERFLOW: 2,  // 溢出
    TIMEOUT: 3   // 过期
  },
  // 本地存储对象
  storage: localStorage || window.localStorage,
  // 获取带前缀的真实键值
  getKey: function (key) {
    return this.prefix + key;
  },
  // 添加(修改)数据
  set: function (key, value, callback, time) {
    ...
  },
  // 获取数据
  get: function (key, callback) {
    ...
  },
  // 删除数据
  remove: function (key, callback) {
    ...
  }
}

添加(修改)数据

/**
  * 添加(修改)数据
  * @param key 数据字段标识
  * @param value 数据值
  * @param callback 回调函数
  * @param time 过期时间
  */
  set: function (key, value, callback, time) {
    // 默认为成功状态
    var status = this.status.SUCCESS,
      key = this.getKey(key);
    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 (key, callback) {
    var key = this.getKey(key),
      status = this.status.SUCCESS,  // 获取数据状态
      value = null;  // 获取数据值

    try {
      // 从本地存储获取数据
      value = this.storage.getItem(key);
    } catch (e) {
      // 获取数据失败
      status = this.status.FAILURE;
      value = null;
    }

    // 如果成功获取数据
    if (status !== this.status.FAILURE) {
      var index = value.indexOf(this.timeSplit),
        timeSplitLen = this.timeSplit.length,
        // 获取时间戳
        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, status, value);
    // 返回结果值
    return value;
  }

删除数据

/**
  * 删除数据
  * @param key 数据字段标识
  * @param callback 回调函数
  */
  remove: function (key, callback) {
    // 设置默认状态为失败
    var status = this.status.FAILURE,
      key = this.getKey(key),
      value = null;
    try {
      // 获取数据值
      value = this.storage.getItem(key);
    } catch (e) {
      // 数据不存在,不采取操作
    }
    // 如果数据存在
    if (value) {
      try {
        // 删除数据
        this.storage.removeItem(key);
        status = this.status.SUCCESS;
      } catch (e) {
        // 数据删除失败,不采取操作
      }
    }
    // 执行回调并传入参数,删除成功则传入被删除的数据值
    callback && callback.call(this, status, status > 0 ? null : value.slice(value.indexOf(this.timeSplit) + this.timeSplit.length));
  }

用法

var dao = new Dao('myModule_');
// 添加/修改数据
dao.set('token', 'abc', function () { console.log(arguments); });
// 获取数据
var value = dao.get('token', function () { console.log(arguments); });
console.log(value);
// 删除数据
dao.remove('token', function () { console.log(arguments); });

写在最后

其实数据访问对象模式更适合与服务器端的数据库操作,比如在nodejs中操作MongoDB,通过对数据库增删改查操作的封装,可以方便我们对前端存储的管理,不必为操作数据库感到烦恼,DAO已经为我们提供了便捷统一的接口,这样在团队开发中就不用担心影响到其他人的数据了。

以上这篇JS设计模式之数据访问对象模式的实例讲解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用JS进行目录上传(相当于批量上传)
Dec 05 Javascript
浏览器打开层自动缓慢展开收缩实例代码
Jul 04 Javascript
理解Javascript闭包
Nov 01 Javascript
select多选 multiple的使用示例
Jun 16 Javascript
jquery获取url参数及url加参数的方法
Oct 26 Javascript
基于JavaScript实现百叶窗动画效果不只单纯flas可以实现
Feb 29 Javascript
利用Ionic2 + angular4实现一个地区选择组件
Jul 27 Javascript
jQuery Ajax向服务端传递数组参数值的实例代码
Sep 03 jQuery
解决webpack无法通过IP地址访问localhost的问题
Feb 22 Javascript
Vue 项目分环境打包的方法示例
Aug 03 Javascript
vue-cli 首屏加载优化问题
Nov 06 Javascript
JS实现的贪吃蛇游戏完整实例
Jan 18 Javascript
浅谈vue的iview列表table render函数设置DOM属性值的方法
Sep 30 #Javascript
iview给radio按钮组件加点击事件的实例
Sep 30 #Javascript
浅谈react-native热更新react-native-pushy集成遇到的问题
Sep 30 #Javascript
jquery之基本选择器practice(实例讲解)
Sep 30 #jQuery
iframe高度自适应及隐藏滚动条的实例详解
Sep 29 #Javascript
H5实现仿flash效果的实现代码
Sep 29 #Javascript
Angular表格神器ui-grid应用详解
Sep 29 #Javascript
You might like
php中使用explode查找某个字符是否存在的方法
2011/07/12 PHP
php中用socket模拟http中post或者get提交数据的示例代码
2013/08/08 PHP
php使用PDO操作MySQL数据库实例
2014/12/30 PHP
php对二维数组进行相关操作(排序、转换、去空白等)
2015/11/04 PHP
Yii2.0高级框架数据库增删改查的一些操作
2015/11/16 PHP
PHP7常量数组用法分析
2016/09/26 PHP
PHP小偷程序的设计与实现方法详解
2016/10/15 PHP
Zend Framework入门教程之Zend_View组件用法示例
2016/12/09 PHP
dojo 之基础篇(二)之从服务器读取数据
2007/03/24 Javascript
jquery select动态加载选择(兼容各种浏览器)
2013/02/01 Javascript
javascript中实现兼容JAVA的hashCode算法代码分享
2020/08/11 Javascript
jQuery对val和atrr("value")赋值的区别介绍
2014/09/26 Javascript
完美兼容各大浏览器的jQuery插件实现图片切换特效
2014/12/12 Javascript
JS实现从顶部下拉显示的带动画QQ客服特效代码
2015/10/24 Javascript
自动完成的搜索框javascript实现
2016/02/26 Javascript
分离与继承的思想实现图片上传后的预览功能:ImageUploadView
2016/04/07 Javascript
js中删除数组中的某一元素实例(无下标时)
2017/02/28 Javascript
vue 2.0路由之路由嵌套示例详解
2017/05/08 Javascript
快速了解vue-cli 3.0 新特性
2018/02/28 Javascript
vue项目引入字体.ttf的方法
2018/09/28 Javascript
微信小程序实现文字跑马灯
2020/05/26 Javascript
从vue源码看props的用法
2019/01/09 Javascript
Vue的H5页面唤起支付宝支付功能
2019/04/18 Javascript
nodejs中实现修改用户路由功能
2019/05/24 NodeJs
Python基础教程之tcp socket编程详解及简单实例
2017/02/23 Python
python3的输入方式及多组输入方法
2018/10/17 Python
Python面向对象基础入门之设置对象属性
2018/12/11 Python
Python调用C语言的实现
2019/07/26 Python
Python-opencv实现红绿两色识别操作
2020/06/04 Python
Python3 pyecharts生成Html文件柱状图及折线图代码实例
2020/09/29 Python
编写用C语言实现的求n阶阶乘问题的递归算法
2014/10/21 面试题
介绍一下write命令
2014/08/10 面试题
校园环保建议书
2014/05/14 职场文书
大学毕业生自我鉴定范文
2019/06/21 职场文书
学校就业保障协议书
2019/06/24 职场文书
nginx 配置缓存
2022/05/11 Servers