数据访问对象模式-前端封装本地数据存储类

数据访问对象模式(Data access object-DAO):抽象和封装对数据源的访问和存储,DAO通过对数据源链接的管理方便对数据的访问和存储。

 

假设我们有一个功能需要本地存取数据实现而非调用后台接口,这个功能并不难,但存在以下问题

  • 数据很可能会覆盖他人的数据或被其他人员覆盖
  • 添加一条数据需要做各个浏览器的兼容
  • 无法知道数据存取的状态成功、失败、过期等
  • 更多一系列的问题

那么,有什么办法可以让每个人方便的管理自己的本地存储库呢?

我们可以创建一个数据访问对象类DAO,这样每个人在自己的模块就可以通过创建这个DAO类的实例来使用了

 

数据访问对象类

一个标准的数据访问对象类需要具备以下条件

  • 可以对数据进行增、删、改、查
  • 可以区分是谁的库(localStorage本地存储没有分库的概念,需要人为去划分)
  • 每一项数据存储都需要设置存储时间(用于定期清除等)

包括但不限于以上条件,下面我们开始创建一个DAO类

/*
 * @description 本地存储类
 * @method BaseLocalStorage
 * @param {String} preId 本地存储数据库前缀
 * @param {String} timeSign 时间戳与存储数据之间的拼接符
*/
var BaseLocalStorage = function(preId, timeSign) {
	// 定义本地存储数据前缀
	this.preId = preId;
	
	// 定义时间戳与存储数据之间的拼接符
	this.timeSign = timeSign || '-';
}

 

数据操作状态

我们可以在DAO类内部保存操作需要返回的状态,并提供对数据进行增删改查的接口

BaseLocalStorage.prototype = {
	// 操作状态
	status: {
		SUCCESS: 0,		// 成功
		FAILURE: 1,		// 失败
		OVERFLOW: 2,	// 溢出
		TIMEOUT: 3		// 过期
	},
	
	// 保存本地存储链接
	storage: localStorage || window.localStorage,
	
	// 获取本地存储数据库数据真实字段
	getKey: function(key) {
		return this.preId + key;
	},
	
	// 添加(修改)数据
	set: function(key, value, callback, time) {
		
	},
	
	// 获取数据
	get: function(key, callback) {
		
	},
	
	// 删除数据
	remove: function(key, callback) {
		
	}
}

 

增添数据

添加数据时,我们需要在字段中添加时间戳,并且我们向本地存储中添加数据实质上是调用localStorage的setItem方法。最后我们还要执行回调函数并将操作的结果传入回调函数中

// 添加(修改)数据
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 * 31;
	}
	
	try {
		// 向数据库中添加数据
		this.storage.setItem(key, time + this.timeSign + value);
	} catch(e) {
		// 溢出失败,返回溢出状态
		status = this.status.OVERFLOW;
	}
	
	// 有回调函数则执行回调函数并传入参数操作状态,真实数据字段标识以及存储数据值
	callback && callback.call(this, status, key, value);
}

 

查找数据

数据查找需要兼容以下四种查询数据情况

  • 该字段的数据本身就不存在,返回失败状态
  • 操作成功但是没有获取到值,返回失败状态
  • 获取到值但是时间已经过期,此时应该删除数据
  • 获取成功并将数据返回
get: function(key, callback) {
	var status = this.status.SUCCESS, // 默认成功
		key = this.getKey(key),
		value = null,
		timeSignLen = this.timeSign.length, // 时间戳与存储数据之间的拼接符长度
		that = this,
		index, // 时间戳与存储数据之间的拼接符起始位置
		time, // 时间戳
		result;
		
	try {
		// 获取字段对应的数据字符串
		value = that.storage.getItem(key);
	} catch(e) {
		// 获取失败则返回失败状态,数据结果为null
		result = {
			status: that.status.FAILURE,
			value: null
		};
		
		callback && callback.call(this, result.status, result.value);
		
		return result;
	}
	
	if (value) {
		// 获取时间戳与存储数据之间的拼接符起始位置
		index = value.indexOf(that.timeSign);
		
		// 获取时间戳
		time = +value.slice(0, index);
		
		// 如果时间为过期
		if (new Date(time).getTime() > new Date().getTime() || time == 0) {
			// 获取数据结果(拼接符后面的字符串)
			value = value.slice(index + timeSignLen);
		} else {
			value = null;
			status = that.status.TIMEOUT;
			that.remove(key);
		}
	} else {
		// 未获取数据字符串状态为失败状态
		status = that.status.FAILURE;
	}
	
	result = {
		status: status,
		value: value
	}
	
	callback && callback.call(this, result.status, result.value);
	
	return result;
}

 

删除数据

删除方法需要兼容以下三种情况

  • 没有该字段,返回失败状态
  • 删除时发生异常,返回失败状态
  • 删除成功
// 删除数据
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) {
			//TODO handle the exception
		}
	}
	
	value = status > 0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length);
	
	// 执行回调,注意传入回调函数中的数据值:如果操作状态成功则返回真实数据结果,否则返回空
	callback && callback.call(this, status, value);
}

测试

var LS = new BaseLocalStorage('LS_');

LS.set('a', 'xiaoming', function() {
	console.log(arguments);
});

LS.get('a', function() {
	console.log(arguments);
})

LS.remove('a', function() {
	console.log(arguments);
})

LS.remove('a', function() {
	console.log(arguments);
})

LS.get('a', function() {
	console.log(arguments);
})

结果正如我们所预期的那样

 

 

最后,附完整代码

/*
 * @description 本地存储类
 * @method BaseLocalStorage
 * @param {String} preId 本地存储数据库前缀
 * @param {String} timeSign 时间戳与存储数据之间的拼接符
*/
var BaseLocalStorage = function(preId, timeSign) {
	// 定义本地存储数据前缀
	this.preId = preId;
	
	// 定义时间戳与存储数据之间的拼接符
	this.timeSign = timeSign || '-';
}

BaseLocalStorage.prototype = {
	// 操作状态
	status: {
		SUCCESS: 0,		// 成功
		FAILURE: 1,		// 失败
		OVERFLOW: 2,	// 溢出
		TIMEOUT: 3		// 过期
	},
	
	// 保存本地存储链接
	storage: localStorage || window.localStorage,
	
	// 获取本地存储数据库数据真实字段
	getKey: function(key) {
		return this.preId + key;
	},
	
	// 添加(修改)数据
	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 * 31;
		}
		
		try {
			// 向数据库中添加数据
			this.storage.setItem(key, time + this.timeSign + value);
		} catch(e) {
			// 溢出失败,返回溢出状态
			status = this.status.OVERFLOW;
		}
		
		// 有回调函数则执行回调函数并传入参数操作状态,真实数据字段标识以及存储数据值
		callback && callback.call(this, status, key, value);
	},
	
	// 获取数据
	get: function(key, callback) {
		var status = this.status.SUCCESS, // 默认成功
			key = this.getKey(key),
			value = null,
			timeSignLen = this.timeSign.length, // 时间戳与存储数据之间的拼接符长度
			that = this,
			index, // 时间戳与存储数据之间的拼接符起始位置
			time, // 时间戳
			result;
			
		try {
			// 获取字段对应的数据字符串
			value = that.storage.getItem(key);
		} catch(e) {
			// 获取失败则返回失败状态,数据结果为null
			result = {
				status: that.status.FAILURE,
				value: null
			};
			
			callback && callback.call(this, result.status, result.value);
			
			return result;
		}
		
		if (value) {
			// 获取时间戳与存储数据之间的拼接符起始位置
			index = value.indexOf(that.timeSign);
			
			// 获取时间戳
			time = +value.slice(0, index);
			
			// 如果时间为过期
			if (new Date(time).getTime() > new Date().getTime() || time == 0) {
				// 获取数据结果(拼接符后面的字符串)
				value = value.slice(index + timeSignLen);
			} else {
				value = null;
				status = that.status.TIMEOUT;
				that.remove(key);
			}
		} else {
			// 未获取数据字符串状态为失败状态
			status = that.status.FAILURE;
		}
		
		result = {
			status: status,
			value: value
		}
		
		callback && callback.call(this, result.status, result.value);
		
		return result;
	},
	
	// 删除数据
	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) {
				//TODO handle the exception
			}
		}
		
		value = status > 0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length);
		
		// 执行回调,注意传入回调函数中的数据值:如果操作状态成功则返回真实数据结果,否则返回空
		callback && callback.call(this, status, value);
	}
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值