2013-05-30 1 views
1

개체 풀링을 사용하면 얻을 수있는 이점을 알 수 있으며이를 벡터와 결합하려고합니다. 그러나 Vectors에 관해서는 컴파일시에만 정의 할 수 있다는 것을 알았습니다. 즉, 각각의 풀링 된 클래스에 대해 별도의 풀러 클래스가 필요하다는 것을 의미합니다. 다른 한편으로는 런타임에 풀에서 풀 (임의의 클래스를 확장)하는 무작위 클래스 인스턴스를 갖고 싶습니다. 따라서 어떤 객체 풀이 호출되는지 정확히 알지 못합니다. 그리고 풀러 클래스의 코드 시퀀스를 곱하지 않으려면 모든 풀을 UniversalPooler 클래스에 결합하여 var foo:SomeClass=UniversalPool.getFromPool(SomeClass);과 같은 요청을 처리 할 수 ​​있습니다. 문제는 가능한 경우 벡터를 사용하여 임의의 하위 클래스 선택을 사용하여 범용 풀러 성능을 효과적으로 구현할 수있는 방법입니다.범용 개체 풀

답변

1

예, 불행히도 Vectors을 사용할 수 없으므로 AS3의 제네릭 구현이 매우 부족합니다.

package util.pool 
{ 
import flash.utils.Dictionary; 

public class ObjectPool 
{ 
    private var storage:Dictionary = new Dictionary(); 

    public function ObjectPool() 
    { 
    } 

    private function createNew(constructor:Class, ...args):Object 
    { 
     //as3 - (facepalm), why there isn't API to path array of params to constructor 
     switch (args.length) { 
      case 0:return new constructor(); 
      case 1:return new constructor(args[0]); 
      case 2:return new constructor(args[0], args[1]); 
      case 3:return new constructor(args[0], args[1], args[2]); 
      case 4:return new constructor(args[0], args[1], args[2], args[3]); 
      case 5:return new constructor(args[0], args[1], args[2], args[3], args[4]); 
      case 6:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5]); 
      case 7:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); 
      case 8:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); 
      case 9:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); 
      case 10:return new constructor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); 
      default: throw new Error("too much arguments for constructor, add more switch cases :))"); 
     }  
    } 

    public function create(constructor:Class, ...args):Object 
    { 
     var pool:Array = getOrCreatePool(constructor); 

     var res:*; 
     if(pool.length > 0) 
     { 
      res = pool.pop(); 
     }else 
     { 
      args.unshift(constructor); 
      res = createNew.apply(null, args); 
     } 

     return res; 
    } 

    public function destroy(obj:Object):void 
    { 
     if(!obj) return; 
     if(!(obj is Object)) return; 

     var constructor:Class = obj["constructor"]; 
     var pool:Array = getOrCreatePool(constructor); 
     pool[pool.length] = obj; 
    } 

    public function destroyArr(objs:Object):void 
    { 
     for each(var obj:Object in objs) 
      destroy(obj); 
    } 

    private function getOrCreatePool(constructor:Class):Array 
    { 
     var pool:Array = storage[constructor]; 
     if(!pool) 
     { 
      pool = []; 
      storage[constructor] = pool; 
     } 

     return pool; 
    } 
} 
} 

그것은 하나 개의 글로벌 풀로 사용할 수 있습니다 : 나는 객체 저장에 대한 클래스지도 DictionaryArrays에 따라 다음 풀링을 사용합니다. 그리고 나는 훨씬 더 효과적인 구현이있을 수 있다고 생각하지 않는다. 그것은 일반적으로 매우 단순한 특징이다.

+0

실제로 Dictionary + 배열을 통해 풀을 만드는 것을 고려하고있었습니다. 이것은 unresizing 배열로 바뀔 수 있다고 생각합니다. IIRC는'pop()'또는'shift()'를 호출하고'push'와'unshift'는 알려진 인덱스에 할당하는 것보다 비용이 많이 듭니다. 그러나 인덱스는 풀과 함께 저장되어야하고 우리는 이미'Dictionary [constructor] '를 한 번 호출하고 있으므로 다른 호출 또는 중첩 된 Object {a : Array, i : 현재 인덱스}는 시프트/터지는 것은 GC로 간다. 이것은 현재의 프로젝트에서는별로 중요하지 않지만 생각과 테스트가 필요합니다. – Vesper

+0

네, 맞아요, 추가 할 때'push' 대신에 인덱스로 지정하지만, 제거를 위해서'pop'을 사용합니다. (현재 인덱스를 유지하고있을 수도 있습니다. 마지막 요소가 null 일 때 더 효과적입니다.). 이러한 테스트를 수행하려는 경우 가장 빠른 풀링 클래스를 기대합니다. – fsbmain

+0

일반 풀 클래스의 구현에 결함이 있습니다.이 목적은 인스턴스가 필요할 때마다 실제로 새 인스턴스를 만드는 것을 방지하기위한 것입니다. ... 각 객체 생성에 대해 args를 사용하면 실제로 객체 인스턴스를 다른 것으로 대체하기 위해 Array를 만듭니다. 구현을 벤치마킹 해 보았고 고정 된 수의 args를 가진 유사한 버전과 비교 했습니까? args의 각 수에 대한 메소드를 복제하는 것이 가장 우아한 해결책은 아니지만 성능을 향하고 있다면 가치가 있어야합니다. – jauboux