开发者

Inheritance problem in javascript

开发者 https://www.devze.com 2023-03-11 06:51 出处:网络
I have the following class hierarchy: Storage Collection EixoCollection OfertaCollection And I have the following code:

I have the following class hierarchy:

  • Storage
    • Collection
      • EixoCollection
      • OfertaCollection

And I have the following code:

var ofertaCollection = new OfertaCollection();
var eixoCollection = new EixoCollection();

ofertaCollection.set('mykey', 'myvalue');
alert(eixoCollection.get('mykey')); // it returns 'myvalue', should return nothing

The problem is that ofertaCollection and eixoCollection have properties referencing each other.

Follow the classes:

/**
 * Storage
 * 
 * @returns {Storage}
 */
function Storage(){

    this.storage = []; // itens that have a key

    // sets key
    this.set = function(key, value){
        this.storage[key] = value;
    }

    // gets key
    this.get = function(key){
        return this.storage[key];
    }
}

/**
 * Collection
 * 
 * @returns {Collection}
 */
function Collection(){

}
Collection.protot开发者_运维技巧ype = new Storage();

/**
 * EixoCollection
 * 
 * @returns {EixoCollection}
 */
function EixoCollection(){
}
EixoCollection.prototype = new Collection();

/**
 * OfertaCollection
 * 
 * @returns {OfertaCollection}
 */
function OfertaCollection(){
}
OfertaCollection.prototype = new Collection();

What is the problem?


Firstly, I suggest two changes in your code (that the examples will use): this.storage should be an object {}, since it looks like you never use it as an array. Also, get and set should be in the prototype, otherwise a new instance of those methods will be created for every instance object (unless a smart compiler optimises them, but we won't assume as much).

Solution 1: you could perform quasi-inheritance, whereby only your storage methods are given to inheriting classes, but not the storage object:

function Storage(){}
storage.prototype = {
    get: function(key){
        return this.storage[key];
    },
    set: function(key, value){
        this.storage[key] = value;
    }
};

function Collection(){
    this.storage = {};
}
Collection.prototype = Storage.prototype; // quasi-inheritance

function EixoCollection(){}
EixoCollection.prototype = new Collection();

function OfertaCollection(){}
OfertaCollection.prototype = new Collection();

var ofertaCollection = new OfertaCollection();
var eixoCollection = new EixoCollection();

ofertaCollection.set('mykey', 'myvalue');
alert(eixoCollection.get('mykey')); // undefined

Solution 2: Real inheritance, but instantiate a new store for every collection, so during the prototype lookup the function finds the local store. This is identical to the above, but the inheritance would be as before. So I'll just replace the line that's different:

Collection.prototype = new Storage(); // real inheritance

The problem with both of these implementations is that they require the inheriting class to do two things, both inherit the methods, and instantiate a store. Not pretty.

The easy alternative, and maybe the most intuitive one is to make each use of Storage a composite object, and not an inherited one. A collection has an internal storage, and some extra functionalities, so it fulfils the has-a mnemonic making composition a valid candidate.


The problem is that both of your collection objects share the same Storage object.

var c1 = new OfteraCollection().prototype.prototype;
var c2 = new ExioCollection().prototype.prototype;
console.log(c1 === c2); // true

To remedy this, you could ditch Collection all together and have each one of your collection objects create their own Storage as their prototype.


Here's the very quick fix - change:

function Collection(){
   // assuming you're doing some initialization here, referencing "this"
}
Collection.prototype = new Storage();

to

function Collection(){
    var that = new Storage();
    // initialize whatever's necessary, using "that"
    return that;
}

or, if you aren't doing any initialization, just:

function Collection(){
    return new Storage();
}

Working example here.

This turns Collection into a Storage factory, which prevents reusing the same Storage objects in the descendants.

0

精彩评论

暂无评论...
验证码 换一张
取 消