JavaScript模仿Apache的ObjectPool


在网上看到了有些同志提到了为Ajax的XMLHttpRequest提供一个对象池,也读了他们给出的实现代码。感觉不是特别理想,于是模仿apache的commons中的ObjectPool的思路写了一个简单的JavaScript版。望指教:

function ObjectPool(poolableObjectFactory) {
  this._poolableObjectFactory = poolableObjectFactory;
  this._idlePool = [];
  this._activePool = [];
}
// 从对象池中租借一个对象,如果目前没有可用的空闲对象则通过poolableObjectFactory创建一个
// 既然是借的,用完记得一定要还哦!
ObjectPool.prototype.borrowObject = function() {
  var object = null;
  var idlePool = this._idlePool;
  var factory = this._poolableObjectFactory;
  if (idlePool.length > 0) {
    object = idlePool.pop();
  }
  else {
    object = factory.makeObject();
  }
  if (object != null) {
    this._activePool.push(object);
    if (factory.activateObject) {
      factory.activateObject(object);
    }
  }
  return object;
}
// 归还一个对象
ObjectPool.prototype.returnObject = function(object) {
  function indexOf(array, object) {
    for (var i = 0; i < array.length; i++) {
      if (array[i] == object) return i;
    }
    return -1;
  }
  if (object != null) {
    var activePool = this._activePool;
    var factory = this._poolableObjectFactory;    
    var i = indexOf(activePool, object);
    if (i < 0) return;    
    if (factory.passivateObject) {
      factory.passivateObject(object);
    }    
    activePool.splice(i, 1);
    this._idlePool.push(object);
  }
}
// 返回当前激活对象的个数
ObjectPool.prototype.getNumActive = function() {
  return this._activePool.length;
}
// 返回当前空闲对象的个数
ObjectPool.prototype.getNumIdle = function() {
  return this._idlePool.length;
}
// 销毁对象池及其中的所有对象
// 如果对象池中的对象需要析构。那么必须实现poolableObjectFactory中的destroyObject方法,同时保证ObjectPool的destroy方法在需要的时候被调用到(例如Window的unload事件中)。
ObjectPool.prototype.destroy = function() {
  var factory = this._poolableObjectFactory;
  function returnObject(object) {
    if (factory.passivateObject) {
      factory.passivateObject(object);
    }
  }
  function destroyObject(object) {
    if (factory.destroyObject) {
      factory.destroyObject(object);
    }
  }
var activePool = this._activePool;
  for (var i = 0; i < activePool.length; i++) {
    var object = activePool[i];
    returnObject(object);
    destroyObject(object);
  }
  var idlePool = this._idlePool;
  for (var i = 0; i < idlePool.length; i++) {
    var object = idlePool[i];
    destroyObject(object);
  }
  this._idlePool = null;
  this._activePool = null;
  this._poolableObjectFactory = null;
}

上面代码中ObjectPool的构造参数poolableObjectFactory的声明如下:

// 注意: 这只是说明,不是真正的代码!
var PoolableObjectFactory = {    
  makeObject: function() {}, // 创建一个新的对象。(必须声明)
activateObject: function(object) {}, // 当一个对象被激活时(即被借出时)触发的方法。(可选)
passivateObject: function(object) {}, // 当一个对象被钝化时(即被归还时)触发的方法。(可选)
destroyObject: function(object) {} // 销毁一个对象。(可选)    
};

  结合XMLHttpRequest创建过程的简陋示例:

// 声明XMLHttpRequest的创建工厂
var factory = {    
  makeObject: function() {
    // 创建XMLHttpRequset对象
    // 注:这里的创建方法不够强壮,勿学!
    if (window.ActiveXObject){
      return new ActiveXObject("Microsoft.XMLHTTP");
    }
    else {
      return new XMLHttpRequest();
    }
  },
passivateObject: function(xhr) {
    // 重置XMLHttpRequset对象
    xhr.onreadystatechange = {};
    xhr.abort();
  }
};
var pool = new ObjectPool(factory); // 创建对象池
// ......
var xhr = pool.borrowObject(); // 获得一个XMLHttpRequest对象
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // ......
    pool.returnObject(xhr); // 归还XMLHttpRequest对象
  }
};
xhr.open(method, url, true);
// ......

最后附上jsUnit的测试用例:

function test_pool() {
  var factory = {
    counter: 0,
makeObject: function() {
      return {id: ++ this.counter};      
    },
activateObject: function(object) {
      object.activated = true;
    },
passivateObject: function(object) {
      object.activated = false;      
    },
destroyObject: function(object) {
      object.destroyed = true;      
    }
  };
  //  
  var pool = new ObjectPool(factory);
  //
  // borrowObject object1
  var object1 = pool.borrowObject();
  assertEquals(object1.id, 1);
  assertTrue(object1.activated);
  assertEquals(factory.counter, 1);
  assertEquals(pool.getNumActive(), 1);
  assertEquals(pool.getNumIdle(), 0);
  //  
  // borrowObject object2
  var object2 = pool.borrowObject();
  assertEquals(object2.id, 2);
  assertTrue(object2.activated);
  assertEquals(factory.counter, 2);
  assertEquals(pool.getNumActive(), 2);
  assertEquals(pool.getNumIdle(), 0);
  //  
  // borrowObject object3
  var object3 = pool.borrowObject();
  assertEquals(object3.id, 3);
  assertTrue(object3.activated);
  assertEquals(factory.counter, 3);
  assertEquals(pool.getNumActive(), 3);
  assertEquals(pool.getNumIdle(), 0);
  //  
  // returnObject object2
  pool.returnObject(object2);
  assertFalse(object2.activated);
  assertEquals(factory.counter, 3);
  assertEquals(pool.getNumActive(), 2);
  assertEquals(pool.getNumIdle(), 1);
  //  
  // returnObject object3
  pool.returnObject(object3);
  assertFalse(object3.activated);
  assertEquals(pool.getNumActive(), 1);
  assertEquals(pool.getNumIdle(), 2);  
  //  
  // returnObject object1
  pool.returnObject(object1);
  assertFalse(object1.activated);
  assertEquals(pool.getNumActive(), 0);
  assertEquals(pool.getNumIdle(), 3);  
  //  
  // destroy the pool
  pool.destroy();
  assertTrue(object1.destroyed);
  assertTrue(object2.destroyed);
  assertTrue(object3.destroyed);
}


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3