Veo patrones que hacen uso de un patrón singleton usando clases ES6 y me pregunto por qué los usaría en lugar de simplemente crear una instancia de la clase en la parte inferior del archivo y exportar la instancia. ¿Hay algún tipo de inconveniente negativo en hacer esto? Por ejemplo:
Instancia de exportación 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;Uso:
import API from './services/api-service'¿Cuál es la diferencia de usar el siguiente patrón Singleton? ¿Hay alguna razón para usar uno del otro? De hecho, tengo más curiosidad por saber si el primer ejemplo que di puede tener problemas de los que no estoy al tanto.
Patrón único:
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;Uso:
import API from './services/api-service'; let api = new API()Yo recomendaría ninguno. Esto es totalmente complicado. Si solo necesita un objeto, ¡no use la sintaxis class ! solo ve por
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' 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'La diferencia es si quieres probar cosas.
Digamos que tiene el archivo de prueba api.spec.js Y que su API tiene una dependencia, como esas Constantes.
Específicamente, el constructor en ambas versiones toma un parámetro, su importación de Constants .
Así que tu constructor se ve así:
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. }); });Ahora, con la instancia de exportación, no hay burlas.
import API from './api'; describe('Singleton', () => { it('should let us mock the constants somehow', () => { const mockConstants = { API_URL: "fake_url" } // erm... now what? }); });Con el objeto instanciado exportado, no puede (fácil y sensatamente) cambiar su comportamiento.
Ambos son caminos diferentes. Exportando una clase como la siguiente
const APIobj = new _API(); export default APIobj; //shortcut=> export new _API()y luego importar como se muestra a continuación en varios archivos apuntaría a la misma instancia y una forma de crear un patrón Singleton.
import APIobj from './services/api-service'Mientras que la otra forma de exportar la clase directamente no es singleton, ya que en el archivo que estamos importando necesitamos actualizar la clase y esto creará una instancia separada para cada nueva clase de exportación únicamente:
export default API;Importación de clase y actualización
import API from './services/api-service'; let api = new API()