The Data Access Object Pattern, also known as DAO pattern, is used to separate low-level data access APIs or operations from high-level business services. The Data Access Object Pattern does not belong to the categories of the 23 commonly defined design patterns, but it is generally regarded as a broad-spectrum technical design pattern.
The Data Access Object Pattern encapsulates access to and storage of data sources, providing a data access object class responsible for managing and manipulating the stored data, and standardizing the data storage format, similar to the backend's DAO layer. HTML5 provides two new methods for client-side data storage: localStorage
and sessionStorage
. They are two storage mechanisms provided by the Web Storage API, with the former being permanent storage and the latter being limited to the current session and data transfer in related windows. Since WebStorage uses a key-value approach to access data and can only store strings (any type of data will be converted to strings when stored and requires type conversion when read), we can standardize the format of the key, such as module name + Key, developer + Key, and also add a prefix to describe the data in the value, such as adding a timestamp for the expiration date of the data to manage the data lifecycle. The specific format can be defined by the project team itself, mainly for ease of management and prevention of conflicts. In the frontend, it mainly involves encapsulating local storage to standardize and define the data access object after the conventions are set.
/**
* LocalStorage data access class
* @param {string} prefix Key prefix
* @param {string} timeSplit Separator between timestamp and stored data
*/
var DAO = function (prefix, timeSplit) {
this.prefix = prefix;
this.timeSplit = timeSplit || "|-|";
}
```javascript
// Prototype method
DAO.prototype = {
constructor: DAO,
// Operation status
status: {
SUCCESS: 0, // Success
FAILURE: 1, // Failure
OVERFLOW: 2, // Overflow
TIMEOUT: 3 // Expired
},
// Local storage object
storage: localStorage || window.localStorage,
/**
* Get the real key value with prefix
* @param key Data field identifier
*/
getKey: function (key) {
return this.prefix + key;
},
/**
* Add (or update) data
* @param key Data field identifier
* @param value Data value
* @param callback Callback function
* @param time Expiration time
*/
set: function (oriKey, value, callback, time) {
let status = this.status.SUCCESS; // Default to success
let key = this.getKey(oriKey);
try{
time = new Date(time).getTime() || time.getTime(); // Get expiration timestamp
}catch(e){
time = new Date().getTime() + 1000 * 60 * 60 * 24 * 30; // Default to one month if no expiration time is set
}
try{
this.storage.setItem(key, time + this.timeSplit + value); // Add (or update) data to local storage
}catch(e){
status = this.status.OVERFLOW; // Overflow occurred
}
callback && callback.call(this, status, key, value); // Execute callback and pass in parameters
},
/**
* Get data
* @param key Data field identifier
* @param callback Callback function
*/
get: function (oriKey, callback) {
let key = this.getKey(oriKey);
let status = this.status.SUCCESS; // Get data status
let value = null; // Get data value
try{
value = this.storage.getItem(key); // Get data from local storage
}catch(e){
status = this.status.FAILURE; // Failed to get data
value = null;
}
// If data is successfully retrieved
if (status !== this.status.FAILURE) {
let index = value.indexOf(this.timeSplit);
let timeSplitLen = this.timeSplit.length;
let time = value.slice(0, index); // Get the timestamp
// Check if the data is not expired
if(new Date(1 * time).getTime() > new Date().getTime() || time === 0) {
value = value.slice(index + timeSplitLen); // Get the data value
}else {
value = null; // Data has expired, delete the data
status = this.status.TIMEOUT;
this.remove(key);
}
}
callback && callback.call(this, status, value); // Execute callback
return value; // Return the result value
},
/**
* Delete data
* @param key Data field identifier
* @param callback Callback function
*/
remove: function (oriKey, callback) {
let status = this.status.FAILURE; // Set the default status to failure
let key = this.getKey(oriKey);
let value = null;
try {
value = this.storage.getItem(key); // Get the data value
}catch(e){
// Data does not exist, no operation is taken
}
if(value){ // If the data exists
try{
// Delete the data
this.storage.removeItem(key);
status = this.status.SUCCESS;
}catch(e) {
// Data deletion failed, no operation is taken
}
}
// Execute callback and pass in parameters, if successful, pass in the deleted data value
let param = status > 0 ? null : value.slice(value.indexOf(this.timeSplit) + this.timeSplit.length);
callback && callback.call(this, status, 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", (...args) => console.log(args)); // [0, "111"]
console.log(value); // 111
dao.remove("token", (...args) => console.log(args)); // [0, "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