5

I'm currently working on a project where the following inheritance structure is used:

var Type = function(a){
  this.a = a;
};

var SubType = function(a){
  Type.call(this, a);
};
SubType.prototype = Object.create(Type.prototype);
SubType.prototype.constructor = SubType;

Now, I'm trying add some object pooling to the equation. The pattern I'm currently using works something like (pseudocode):

Type.new = function(){
  if object available in pool
    reset popped pool object 
    return pool object
  else
    return new Type()
}
var a = Type.new();

Of course, the problem with using these two patterns is that constructor calls on SubType wont draw from Type's pool. Is there a way around this without moving to a factory structure? I.e. is there a way, in a constructor, to do something along the lines of:

var SubType = function(){
  build on top of instanceReturnedFromFunction()
};

Knowing it's not always consistent across contexts, I'd would also like to preserve the inheritance structure so that instanceof etc will still work:

  • What is a "factory structure" and why do you want to avoid that? – Bergi Jul 12 '15 at 16:51
  • By factory structure, I mean refactoring from constructors / new to something along the lines of `function Type(a){ return {a: a} }`. As to why: it would involve a quantity of refactoring, and would exclude the use some inbuilt operators (instanceof etc.) –  Jul 12 '15 at 20:21
  • Ah, I see. I thought you meant the `Type.new` factory… – Bergi Jul 12 '15 at 20:26

1 Answers1

3

The problem with using this pattern is that constructor calls on SubType wont draw from Type's pool

In fact that's not a problem, that's a necessity. Type and SubType instances do have different prototypes, you cannot use them interchangeably (and swapping prototypes doesn't work either).
You definitely will need separate pools for all your classes. And you can use that .new factory approach without any problems - though of course you should create those factories programatically:

function pooledNew() {
    // `this` is the "class" constructor function
    if (!this.pool) this.pool = [];
    var instance = this.pool.length ? this.pool.pop() : Object.create(this.prototype);
    this.apply(instance, arguments); // reset / initialise
    return instance;
}
function makePooling(constr) {
    constr.new = pooledNew;
    constr.pool = [];
    var proto = constr.prototype;
    if (proto.constructor !== constr)
        proto.constructor = constr;
    if (typeof proto.destroy != "function")
        proto.destroy = function destroyInstance() {
            this.constructor.pool.push(this);
        };
    return constr;
}

These are designed to work flawlessly with subclassing, in your example just do

makePooling(Type);
makePooling(SubType);

In ES6, subclasses even would inherit the new method from their superclass constructors.

class Type {
    constructor(a) {
        this.a = a;
    }
    destroy() { // overwriting default behaviour
        this.a = null; // for GC
        this.constructor.pool.push(this);
    }
}
makePooling(Type);

class SubType extends Type {
    // you can use super calls in both "constructor" and "destroy" methods
}
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Brilliant. Thanks for the info. I haven't got the rep to up-vote the answer yet, but I've marked it as accepted: answers my question! Thanks again. –  Jul 12 '15 at 20:52
  • 1
    @MrMe: You now have the privilege :-) Well-written question asker, welcome to Stack Overflow! – Bergi Jul 12 '15 at 21:01