Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Implementación del patrón Singleton

33/42
Recursos

Aportes 38

Preguntas 16

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Singlenton con TS

Uno de los patrones de diseño de creación más populares es el patrón Singleton que restringe la creación de instancias de una clase a un objeto.

En esta publicación, le mostraré cómo usar el patrón junto con TypeScript.


Es genial con TS

La biblia de los patrones de diseño, a saber, el libro de Gang of Four (GoF), presenta la aplicación de patrones utilizando el lenguaje C ++, un lenguaje estáticamente tipado.

TypeScript permite implementar el patrón Singleton gracias a las siguientes características:

  • soporte para modificadores de acceso (privado, protegido, público),
  • soporte para métodos estáticos,
  • siendo un lenguaje estáticamente escrito.

Patrón Singleton

En el siguiente ejemplo, creo la clase ActionsBus que se supone que se instancia solo una vez, ya que debería haber un único punto para enviar una acción. Además, debe ser notificado sobre cada acción en el sistema simplemente suscribiéndose en un lugar.

import { BehaviorSubject } from 'rxjs';

interface Action {
  type: string;
}

class ActionsBus {
  private static instance: ActionsBus;
  private actionsSubject = new BehaviorSubject<Action>(null);

  get actions$() {
    return this.actionsSubject.asObservable();
  }

  private constructor() {
  }

  static getInstance(): ActionsBus {
    if (!ActionsBus.instance) {
      ActionsBus.instance = new ActionsBus();
    }

    return ActionsBus.instance;
  }

  dispatch(action: Action) {
    this.actionsSubject.next(action);
  }
}

Los puntos clave son:

  • constructor con un modificador de acceso privado, para que no sea accesible fuera del cuerpo de la clase,
  • instancia estática archivada que se supone que hace referencia a la instancia única de la clase,
  • Método getInstance estático que se encarga de devolver la instancia de la clase. Además, sigue una estrategia de evaluación perezosa, por lo tanto, debe crear la instancia cuando se llama por primera vez.

Singleton en acción

Veamos si la clase ActionsBus es un singleton, es decir, si solo hay una instancia de la clase.

//illegal since the constructor is private
const illegalActionsBus = new ActionsBus();

const firstActionsBus = ActionsBus.getInstance();
const secondActionsBus = ActionsBus.getInstance();

//both constants reference the same object
console.log(firstActionsBus === secondActionsBus);

firstActionsBus.actions$.subscribe(console.log);
secondActionsBus.dispatch({ type: 'Fetch news' })

//console output
//{type: "Fetch news"}

Es ilegal crear la instancia de clase de forma tradicional fuera del cuerpo de la clase. Para obtener una referencia a la instancia única de ActionsBus , debe llamar al método estático getInstance . Ambas constantes ( primer / segundo ActionsBus ) hacen referencia al mismo objeto, por lo tanto, la comparación lógica produce verdadero . Por último, pero no menos importante, si se suscribe a la acción $ stream con la ayuda de la referencia firstActionsBus , recibirá una acción enviada utilizando la referencia secondActionsBus . Definitivamente confirma que solo hay una instancia de la clase ActionsBus en el sistema.


Conclusiones

Espero que les haya gustado la publicación y hayan aprendido algo nuevo. El patrón Singleton es uno de los patrones más fáciles de entender, por lo tanto, es un buen punto de partida para familiarizarse con los patrones. Recuerdo que cuando me uní al mundo de JavaScript, estaba un poco molesto porque, debido a la falta de tipeo, el conocimiento sobre los patrones de diseño no sería tan útil como en Java o C ++. Afortunadamente, TypeScript al rescate!

Un concepto que creo que es importante y no se ha tratado en el curso que ayuda a entender el ejercicio son los métodos estáticos.
Estos nos permiten acceder a ellos sin la necesidad de instanciar la clase a la que pertenecen, por eso es que podemos hacer :

Singleton.getInstance();

Sin la necesidad de haber instanciado la clase Singleton, es como un tipo de método público por decirlo así.

En esta clase usamos el keyword static para definir Metodos/Propiedasdes de la clase y no de instancia.

Ejemplo:

class Circle {
    static pi = 3.14;
    pi = 3;
}

Circle.pi; // returns 3.14

let circleObj = new Circle();
circleObj.pi; // returns 3

primera clase que ni fu , ni fa. Quede igual

El index.html que usamos en esta clase:

<html>
  <head>
    <title>Singleton</title>
  </head>

  <body>
    <script src="/ejercicios/singleton/index.ts"></script>
  </body>
</html>

Una pregunta, ¿static tiene la misma intención que en otros lenguajes? como en Java se usa static para definir un método de un objeto que no necesita instancia para ejecutarse.

La ventaja de Singleton es que te ayuda a ahorrar recursos ya que es una única instancia, igual recomiendo el curso de Buenas Prácticas de escritura de código para complementar esto:3

Exactamente el ejemplo del modal, si usara el patron singleton para crear el modal de una aplicación en react podría evitar que se duplique?

Ya estoy enamorado de Typescript, cuando llegue DENO esto va a ser una barbaridad de poder!!!

No se si estoy en lo correcto, pero no se por que se me parece tanto a react este patrón

import Singleton from './singleton';

// en la primera linea, como no existe la instancia, la va a crear
const a = Singleton.getInstance();
// aqui, como ya existe, en este caso solo nos va a devolver la instancia
const b = Singleton.getInstance();

// por lo tanto, a y b van a ser exactamente igual, es la misma instancia.
a === b ? console.log("a y b son iguales") : console.log("No son iguales"); // "a y b son iguales"

He visto que este patrón lo implementan en varias aplicaciones. Un caso de uso es para el Game Manager de un videojuego en Unity (implementado en C#), el cual maneja la lógica principal del juego (control de vida, puntuación, llamada a otras clases y métodos), aquí se aplica este patrón para asegurar que solo haya un objeto que controle la lógica y no haya solapamiento con otro posible controlador.

Les dejo este otro ejemplo por si necesitan reforzar:

class Office {
  private static instance: Office;

  name: string;

  employees: number;

  constructor(name: string, employees: number) {
    this.name = name;
    this.employees = employees;

    if (typeof Office.instance === 'object') {
      return Office.instance;
    }

    Office.instance = this;
    return this;
  }
}

const firstOffice = new Office('Principal', 30);
console.log(firstOffice);
const secondOffice = new Office('Diagonal', 50);
console.log(secondOffice);

Interesante… gracias!!

Singleton restringe la creación de instancias de una clase a un objeto.

¿hay forma de hacer un singleton sin typescript?

Dejo aquí un vídeo que me ayudo a entenderlo mucho mejor
aquí el vídeo de youtube

Excelente implementación y explicación

yo use singleton cuando quería mantener la instancia de la ventana secundaria, cada vez que le daban clic al botón de nueva ventana solo les devolvía la instancia de la ventana que ya existía.

Buena clase!

Encontré este video, que con un ejemplo similar amplía más la explicación
Se los recomiendo
Y lo hace en TS
https://www.youtube.com/watch?v=Qckwuge7dpQ

Si quieres saber más acerca de Singleton, te dejo por aquí un enlace a un vídeo que habla acerca de éste patrón 😄

Excelente explicación.
Como aporte me gustaría dejar un articulo donde se habla sobre el keyword static, por si alguien al igual que yo no le queda del todo claro, espero sea de ayuda.
static clases javascript es6

Excelente.

Otra url sobre patrones

Genial Clase

Cool.

excelente clase, repasnadola*.*

Muy bien expicado gracias

Singleton el mas usado y mas criticado

Buena!

Aun soy reacio a usar typescript asi que lo hice asi:
como regreso verdadero, supongo que esta bien.
Singleton en JS

Aporte

Considerando que igual podemos usar el keyword new , para bloquear en su totalidad esta posibilidad y evitar bugs al implementar el patrón de diseño Singleton, creo que pudieramos interceptar la instanciación de la clase Singleton, y retornar un error,

Muestro a continuación un ejemplo. Corrijanme si ven mejoras.

Creando la clase Singleton

class Singleton {
  private static instance: Singleton;
  private constructor() {}
  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}

const handler = {
  construct() {
    throw Error(
      "BusinessError: you can´t instance the Singleton Class, using the `new` keyword, please use Singleton.getInstance()"
    );
  },
};

const SingletonIntercepted = new Proxy(Singleton, handler);

export default SingletonIntercepted;

Llamando a la clase

import Singleton from "./Singleton";

const a = Singleton.getInstance();
const b = Singleton.getInstance();
const c = new Singleton();

console.log("A equals B", a === b);
console.log("A equals C", a === c);

Al hacer esto, en el navegador dará un error cuando usen el new

Código usando durante la clase:
index.ts

import Singleton from './Singleton';

const a : Singleton = Singleton.getInstance();

const b : Singleton =Singleton.getInstance();


console.log("A es igual a B?",a === b);

Singleton.ts

class Singleton {
    private static instance:Singleton;

    private constructor(){}

    static getInstance(){
        if(!Singleton.instance){
            Singleton.instance = new Singleton();
        }

        return Singleton.instance;
    }
}

export default Singleton;

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Singleton</title>
</head>
<body>
    
    <script src="./index.ts"></script>
</body>
</html>

Este vídeo lo explica de manera muy buena: https://youtu.be/GGq6s7xhHzY