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 相关文章推荐
jquery 插件开发方法小结
Oct 23 Javascript
js过滤HTML标签以及空格的思路及代码
May 24 Javascript
Javascript 数组排序详解
Oct 22 Javascript
JavaScript中的原型prototype属性使用详解
Jun 05 Javascript
JavaScript实现点击自动选择TextArea文本的方法
Jul 02 Javascript
浅析BootStrap中Modal(模态框)使用心得
Dec 24 Javascript
微信小程序 UI与容器组件总结
Feb 21 Javascript
动手写一个angular版本的Message组件的方法
Dec 16 Javascript
js实现多个倒计时并行 js拼团倒计时
Feb 25 Javascript
关于vue3默认把所有onSomething当作v-on事件绑定的思考
May 15 Javascript
js实现拖拽与碰撞检测
Sep 18 Javascript
javascript实现时钟动画
Dec 03 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下保存远程图片到本地的办法
2010/08/08 PHP
PHP经典算法集锦【经典收藏】
2016/09/14 PHP
Laravel框架生命周期与原理分析
2018/06/12 PHP
PHP 获取客户端 IP 地址的方法实例代码
2018/11/11 PHP
laravel框架邮箱认证实现方法详解
2019/11/22 PHP
extjs 时间范围选择自动判断的实现代码
2014/06/24 Javascript
浅谈重写window对象的方法
2014/12/29 Javascript
JS实现可调整倒计时间代码分享
2015/08/18 Javascript
【经典源码收藏】jQuery实用代码片段(筛选,搜索,样式,清除默认值,多选等)
2016/06/07 Javascript
JS实现隐藏同级元素后只显示JS文件内容的方法
2016/09/04 Javascript
bootstrap fileinput实现文件上传功能
2017/08/23 Javascript
JS使用tofixed与round处理数据四舍五入的区别
2017/10/25 Javascript
vue-cli项目中使用Mockjs详解
2018/05/14 Javascript
使用ng-packagr打包Angular的方法示例
2018/09/21 Javascript
这15个Vue指令,让你的项目开发爽到爆
2019/10/11 Javascript
ant-design-vue 快速避坑指南(推荐)
2020/01/21 Javascript
vue实现短信验证码输入框
2020/04/17 Javascript
[00:12]2018DOTA2亚洲邀请赛 sylar表现SOLO技艺
2018/04/06 DOTA
Python中不同进制的语法及转换方法分析
2016/07/27 Python
详解supervisor使用教程
2017/11/21 Python
Python基于生成器迭代实现的八皇后问题示例
2018/05/23 Python
搭建python django虚拟环境完整步骤详解
2019/07/08 Python
Python实现的爬取豆瓣电影信息功能案例
2019/09/15 Python
css3 transform 3d 使用css3创建动态3d立方体(html5实践)
2013/01/06 HTML / CSS
澳大利亚在线奢侈品时尚零售平台:Azura Runway
2021/01/13 全球购物
如果让你测试一台高速激光打印机,你都会进行哪些测试
2012/12/04 面试题
大专学生推荐信范文
2013/11/19 职场文书
人事行政主管岗位职责
2013/12/22 职场文书
道路交通安全实施方案
2014/03/12 职场文书
幼儿园新年寄语
2014/04/03 职场文书
竞选副班长演讲稿
2014/04/24 职场文书
2014年乡镇党建工作总结
2014/11/11 职场文书
重阳节主题班会
2015/08/17 职场文书
车间班组长竞聘书
2015/09/15 职场文书
三好学生竞选稿
2015/11/21 职场文书
SpringBoot2零基础到精通之异常处理与web原生组件注入
2022/03/22 Java/Android