web-dev-qa-db-fra.com

ES6 Singleton vs Instanciation d'une classe une fois

Je vois des modèles qui utilisent un modèle singleton à l'aide de classes ES6 et je me demande pourquoi je les utiliserais au lieu d'instancier la classe au bas du fichier et d'exporter l'instance. Y at-il une sorte d'inconvénient négatif à faire cela? Par exemple:

Instance d'exportation ES6:

import Constants from '../constants';

class _API {
  constructor() {
    this.url = Constants.API_URL;
  }

  getCities() {
    return fetch(this.url, { method: 'get' })
      .then(response => response.json());
  }
}

const API = new _API();
export default API;

Utilisation:

import API from './services/api-service'

Quelle est la différence avec le motif Singleton suivant? Y a-t-il des raisons pour utiliser l'un de l'autre? En fait, je suis plus curieux de savoir si le premier exemple que j'ai donné peut avoir des problèmes dont je ne suis pas au courant.

Singleton Pattern:

import Constants from '../constants';

let instance = null;

class API {
  constructor() {

    if(!instance){
      instance = this;
    }

    this.url = Constants.API_URL;

    return instance;
  }

  getCities() {
    return fetch(this.url, { method: 'get' })
      .then(response => response.json());
  }
}

export default API;

Utilisation:

import API from './services/api-service';

let api = new API()
18
Aaron

La différence est si vous voulez tester des choses.

Disons que vous avez le fichier test api.spec.js. Et que votre chose API a une dépendance, comme ces constantes.

Plus précisément, le constructeur de vos deux versions prend un paramètre, votre importation Constants.

Donc, votre constructeur ressemble à ceci:

class API {
    constructor(constants) {
      this.API_URL = constants.API_URL;
    }
    ...
}



// single-instance method first
import API from './api';
describe('Single Instance', () => {
    it('should take Constants as parameter', () => {
        const mockConstants = {
            API_URL: "fake_url"
        }
        const api = new API(mockConstants); // all good, you provided mock here.
    });
});

Maintenant, avec l'instance d'exportation, on ne se moque pas.

import API from './api';
describe('Singleton', () => {
    it('should let us mock the constants somehow', () => {
        const mockConstants = {
            API_URL: "fake_url"
        }
        // erm... now what?
    });
});

Avec un objet instancié exporté, vous ne pouvez pas (facilement et en toute sécurité) changer son comportement.

10
Zlatko

Je recommanderais ni l'un ni l'autre. C'est totalement compliqué. Si vous n'avez besoin que d'un seul objet, n'utilisez pas la syntaxe class ! Allez juste pour

import Constants from '../constants';

export default {
  url: Constants.API_URL,
  getCities() {
    return fetch(this.url, { method: 'get' }).then(response => response.json());
  }
};

import API from './services/api-service'

ou encore plus simple

import Constants from '../constants';

export const url = Constants.API_URL;
export function getCities() {
  return fetch(url, { method: 'get' }).then(response => response.json());
}

import * as API from './services/api-service'
24
Bergi

Une autre raison d'utiliser Singleton Pattern est que dans certains frameworks (tels que Polymer 1.0), vous ne pouvez pas utiliser la syntaxe export.
C'est pourquoi la deuxième option (modèle Singleton) est plus utile, pour moi.

J'espère que ça aide.

2
Peter

Les deux font la même chose. Le premier est 100% es6. La seconde est l’ancienne méthode qui vient d’être réécrite dans es6.

J'irais avec le premier à tout moment, les nouveaux développeurs ne comprendront pas pourquoi vous devez compliquer les choses, si es6 est ce qu'ils ont commencé avec

0