zoukankan      html  css  js  c++  java
  • javascript ORM

    javascript ORM

    前端ORM框架其实也就是一个对于DAO数据访问接口的封装,主要是封装CRUD四种类型基本操作。
    所谓对象关系映射的构建,最基本的还是在于模型这一层,也就是数据模型,我们应该用对象来封装我们的数据,以形成模型。
    例如一个基本的数据结构为:

    1 var data = {
    2     name: 'ken',
    3     age: 18
    4 };

    我们需要将这样一个数据转化为一个对象,可以将之作为一个参数传递到一个具有某些功能的对象中去,例如:

     1 function Model(data) {
     2     this.data = data;
     3 }
     4 Model.prototype.save = function() {
     5     //do create or update
     6 };
     7 Model.prototype.read = function() {
     8     
     9 };
    10 Model.prototype.delete = function() {
    11     
    12 };
    13 Model.prototype.get = function(attr) {
    14     return this.data[attr];
    15 };

    上面的代码定义了一个基本的数据模型,这个能够完成与服务器之间的数据交互,而数据最终还是需要展现在页面上的,这就需要另外一个对于数据和视图之间的处理了。数据变化之后能够通知页面进行重新渲染,我们可以使用比较常用的一种设计模式,也就是发布/订阅模式来完成这种事件的交互。在数据层发布事件,在视图层去监听事件。我们可以在网上找到很多实现了该功能的代码,其原理也很简单,只需要维护一个用于保存事件名和相应事件的Map表即可,下面是一个实现代码:

     1 var Events = Spine.Events = {
     2     bind: function(ev, callback) {
     3       var evs   = ev.split(" ");
     4       var calls = this._callbacks || (this._callbacks = {});
     5       
     6       for (var i=0; i < evs.length; i++)
     7         (this._callbacks[evs[i]] || (this._callbacks[evs[i]] = [])).push(callback);
     8 
     9       return this;
    10     },
    11 
    12     trigger: function() {
    13       var args = makeArray(arguments);
    14       var ev   = args.shift();
    15             
    16       var list, calls, i, l;
    17       if (!(calls = this._callbacks)) return this;
    18       if (!(list  = this._callbacks[ev])) return this;
    19       
    20       for (i = 0, l = list.length; i < l; i++)
    21         if (list[i].apply(this, args) === false)
    22           return false;
    23       return this;
    24     },
    25 
    26     unbind: function(ev, callback){
    27       if ( !ev ) {
    28         this._callbacks = {};
    29         return this;
    30       }
    31       
    32       var list, calls, i, l;
    33       if (!(calls = this._callbacks)) return this;
    34 
    35       if (!(list  = this._callbacks[ev])) return this;
    36       
    37       if (!callback) {
    38         delete this._callbacks[ev];
    39       }
    40       
    41       for (i = 0, l = list.length; i < l; i++) {
    42         if (callback === list[i]) {
    43           list.splice(i, 1);
    44           break;
    45         }
    46       }
    47         
    48       return this;
    49     }
    50   };

    我们可以给任何需要用到发布订阅模式的对象继承该Event对象,然后我们便可以很方便的发布/订阅事件了。
    当然,我们的对象默认情况下并没有一个可直接使用的继承方法,但是要实现基层并不难,我们可以给我们的Model对象添加下面这两个方法:

     1 Model.include = function(obj){
     2   for(var key in obj) {
     3       this.prototype[key] = obj[key];
     4   }
     5 
     6   var included = obj.included;
     7   if (included) included.apply(this);
     8   return this;
     9 },
    10 
    11 Model.extend = function(obj){
    12   for(var key in obj) {
    13       this[key] = obj[key];
    14   }
    15   
    16   var extended = obj.extended;
    17   if (extended) extended.apply(this);
    18   return this;
    19 }

    有了上面的两个方法之后,我们便可以通过include方法来扩展实例方法,通过extend来扩展静态方法,对于Event,我们可以用extend来进行扩展:

    1 Model.extend(Event);

    扩展完成之后,我们便可以在我们的代码中添加事件的发布或者订阅了,在模型中有关于数据保存或者更新的地方我们可以发布change事件,在数据销毁的时候我们可以发布destroy事件:

    1 Model.prototype.save = function() {
    2     //todo create or update
    3     this.trigger('change');
    4 };
    5 Model.prototype.delete = function() {
    6     //todo delete
    7     this.trigger('destroy');
    8 }

    在页面中,我们会根据得到的数据来生成对应的模型,因为我们的模型已经扩展了发布订阅模式,因此在代码中,我们给我们的模型添加订阅事件的代码:

    1 //子视图
    2 function View(data) {
    3     var model = new Model(data);
    4     model.bind('change', this.render);
    5 }
    6 View.prototype.render = function() {
    7     //todo view render
    8 };

    上面便是前端ORM的一个基础框架模型,也是核心点所在,不过要完成整个框架,仍然需要添加很多的东西。
    上面的代码仅仅是能实现唯一的模型实例,而不能对模型实例集合进行操作,什么意思呢,比如你的数据是一个数组,
    里面包含了多条数据,没一条数据都能转换为一个对象的模型对象。在现在的代码中,我们只完成了一条数据的转换而没有完成整个数据数据的转换,因此,需要做出一些调整;
    在服务器端获取回来的数据,我们应该将之转换为一个模型,数据集里面的每一个数据记录,就用来转换成为该模型的每一个实例,按照这个思路,我们的代码使用起来可能像下面这个样子:

    1 var User = Model.create();
    2 var user = User.init();

    模型的创建,也就是User的创建,我们是不需要传递数据的,只需要传递我们需要的一些数据字段即可,这些字段也就是模型实例的一些内置属性;根据User来生成的实例都会具有User所具有的一些信息,在这里就是字段属性。
    同时Model还应该具有一些静态方法用来查找实例,修改实例等,因此该Model还要有一个用于保存模型实例的容器,也就是一个数组或者对象。

     1 Model.extend({
     2     records: {}, //保存实例
     3     find: function(id) {
     4 
     5     },
     6     exists: function(id) {
     7 
     8     },
     9     ...
    10 });

    至此,一个大致的ORM构建思路就算是完成了,具体的代码还需要不断的添加完成。

  • 相关阅读:
    拷贝构造函数与赋值函数的区别
    C++模板(一)
    拷贝构造函数
    memcpy函数
    malloc calloc 和 realloc
    extern关键字
    C中不安全函数
    缓冲区溢出问题
    C++引用
    背包问题专栏(01,完全,多重)
  • 原文地址:https://www.cnblogs.com/moyiqing/p/orm.html
Copyright © 2011-2022 走看看