2016-04-28 17 views
8

Sto pensando a un problema semplice. Ho dato una classe ad esempio ModelCome gestire l'oggetto di classe con riferimenti circolari?

class Model { 
    constructor(parameters = {}) { 
     this.id = parameters.id; 
    } 
} 

così come si può vedere siamo in grado di creare nuovi oggetti come Model: let model = new Model(). Altro esempio complesso sarebbe simile a questa:

//we have some data given from API maybe? 
let parameters = {id: 1}; 
let model = new Model(parameters); 

E qui siamo al punto in cui ho iniziato a vagare Che cosa succede se l'oggetto con data id esiste già?

La domanda è quale modello dovrei usare per istanziare l'oggetto con data id una sola volta?

Andiamo oltre: cosa succede se otterremo oggetti nidificati con riferimenti circensi? Lasciate assumere abbiamo ottenuto un'altra classe chiamata AnotherModel e il nostro codice è simile:

class Model { 
    constructor(parameters = {}) { 
     this.id = parameters.id; 
     this.anotherModel= nulld; 

     if (parameters.anotherModel) { 
      this.anotherModel= parameters.anotherModel instanceof AnotherModel 
       ? parameters.anotherModel 
       : new AnotherModel(parameters.anotherModel); 
     } 
    } 
} 

class AnotherModel { 
    constructor(parameters = {}) { 
     this.id = parameters.id; 
     this.models = []; 

     if (parameters.models) { 
      for (let i = 0; i < parameters.models.length; i++) { 
       let model = parameters.models[i]; 
       model.anotherModel= this; 
       this.models.push(new Model(model)); 
      } 
     } 
    } 
} 

Così AnotherModel contiene una raccolta di Model s e Model oggetto contiene riferimento alla AnotherModel.

Qual è il modo per risolvere questo problema? Ciò che vogliamo ottenere è avere un solo oggetto con lo stesso id.

Quello che stavo pensando è fare una specie di ObjectPool in cui memorizzerò tutti gli oggetti per una determinata classe o classe e quando il nuovo oggetto viene istanziato il nostro pool ne creerebbe uno nuovo se non esiste o restituisce quello esistente?

Ma qui è un po 'di disadattamento, se per esempio abbiamo già scritto del codice dovremmo rifattorizzare e cambiare il modo in cui li instiamo da new Model() a ObjectPool.get(Model, parameters)?

Quali sono le tue idee?

+0

nello scenario di cui sopra, è un esempio di 'AnotherModel' creato per primo?Oppure le istanze di 'Model' e' AnotherModel' possono essere create singolarmente? Non sono sicuro di aver capito come dovrebbe funzionare il tuo codice. – nils

+0

singolarmente, non importa se prima creiamo un 'AnotherModel' o 'Model' – Vardius

+0

Mi dispiace se questa è una domanda stupida, ma è necessario che entrambi i componenti mantengano un riferimento l'uno con l'altro? Soprattutto questa linea non ha molto senso per me: ': new AnotherModel (parameters.anotherModel);' (creando 'AnotherModel' dal Model senza passare nello stesso' Modello ') – nils

risposta

3

È possibile utilizzare un pool di oggetti (sulla classe o al di fuori di esso) per tenere traccia delle istanze. Definendo nel costruttore, è ancora possibile istanziare i modelli con:

new Model(); 
new AnotherModel(); 

Se il id esiste già in piscina, si può semplicemente restituire l'istanza esistente.

Al di fuori della classe:

const modelPool = {}; 

class Model { 
    constructor(parameters = {}) { 
     if (modelPool[parameters.id] instanceof Model) { 
      return modelPool[parameters.id]; 
     } 

     modelPool[parameters.id] = this; 

     this.id = parameters.id; 
     this.anotherModel= null; 

     // ... 
    } 
} 

const anotherModelPool = {}; 

class AnotherModel { 
    constructor(parameters = {}) { 
     if (anotherModelPool[parameters.id] instanceof AnotherModel) { 
      return anotherModelPool[parameters.id]; 
     } 

     anotherModelPool[parameters.id] = this; 

     this.id = parameters.id; 
     this.models = []; 

     //... 
    } 
} 

O come un (non numerabile, non scrivibile, non configurabile) Proprietà sulla classe (non l'istanza):

class Model { 
    constructor(parameters = {}) { 
     if (Model.pool[parameters.id] instanceof Model) { 
      return Model.pool[parameters.id]; 
     } 

     Model.pool[parameters.id] = this; 

     this.id = parameters.id; 
     this.anotherModel= null; 

     //... 
    } 
} 

Object.defineProperty(Model, 'pool', { 
    value: {} 
}); 

class AnotherModel { 
    constructor(parameters = {}) { 
     if (AnotherModel.pool[parameters.id] instanceof AnotherModel) { 
      return AnotherModel.pool[parameters.id]; 
     } 

     AnotherModel.pool[parameters.id] 

     this.id = parameters.id; 
     this.models = []; 

     //... 
    } 
} 

Object.defineProperty(AnotherModel, 'pool', { 
    value: {} 
}); 

Come aggiunto da @Vardius, si può anche creare una classe pseudo-astratta (poiché JS non ha classi astratte) da cui può essere esteso. Utilizzando new.target.name, è possibile creare uno spazio dei nomi all'interno del pool della classe astratta:

class Entity { 
    constructor(parameters = {}) { 
     if (Entity.pool[this.constructor.name] && Entity.pool[this.constructor.name][parameters.id] instanceof Entity) { 
      return Entity.pool[new.target.name][parameters.id]; 
     } 
     Entity.pool[new.target.name][parameters.id] = this; 
    } 
} 
Object.defineProperty(Entity, 'pool', {value: {} }); 
+0

e se creo una classe astratta 'AbstractModel' e definirò la proprietà' pool' solo per questa classe e quindi tutti gli altri modelli la estenderanno. funzionerà ? – Vardius

+0

dovrei definire la matrice quindi per memorizzare anche 'constructor.name' per più classi – Vardius

+0

Probabilmente no, perché' pool' non dovrebbe essere un'istanza ('this.pool') o un prototipo (' AbstractModel.prototype.pool') proprietà. Se fosse una proprietà di istanza, non funzionerebbe come sarebbe stata creata per ogni istanza. A meno che non si possa scrivere sul pool come proprietà sulla classe 'AbstractModel' nel costruttore' AbstractModel' e mantenere uno spazio dei nomi per tutti i childclass. – nils