Fermer

août 27, 2024

Le modèle de conception Singleton en JavaScript : un guide complet

Le modèle de conception Singleton en JavaScript : un guide complet


Introduction

Qu’est-ce que le modèle de conception Singleton ?

Le modèle de conception Singleton limite l’instanciation d’une classe à une seule instance. Ceci est avantageux lorsqu’un seul objet ou une ressource partagée est requis pour coordonner les actions dans l’ensemble du système. C’est particulièrement pratique pour gérer des ressources ou des données partagées entre différentes instances d’une classe. Par exemple, un pool de connexions à une base de données ou un gestionnaire de configuration peut être implémenté en tant que singleton pour garantir un accès cohérent et éviter les conflits de ressources.

Le besoin d’un modèle de conception Singleton

  • Objets de configuration : Gérez les paramètres de l’application sur divers composants sans avoir à créer plusieurs instances de l’objet de configuration.
  • Connexions à la base de données : Conserver un pool de connexions à la base de données unique qui peut être réutilisé par différentes parties de l’application, ce qui est crucial pour l’efficacité et l’évolutivité.
  • Enregistrement: Implémentation d’un utilitaire de journalisation qui centralise le mécanisme de journalisation au lieu de créer plusieurs instances du logger.

Deux formes d’initialisation singleton :

  1. Initialisation précoce – Dans cette stratégie, l’instance singleton est créée au moment du chargement de la classe. Cela signifie que l’instance est créée et consomme des ressources même si elle n’est jamais utilisée pendant la durée de vie de l’application.

  2. Initialisation paresseuse – Dans cette stratégie, l’instance singleton est créée uniquement lorsqu’elle est nécessaire pour la première fois. Cela retarde la création de l’instance jusqu’au moment où elle est accessible, économisant ainsi des ressources si elle n’est jamais utilisée.

Voyons un exemple de base sur le fonctionnement du singleton, puis nous verrons comment nous avons implémenté ce modèle dans un projet en direct.

class Singleton { 
 constructor() { 

  if (Singleton.instance) { 
     // Singleton instance already exists.
     return Singleton.instance; 
  } 

  Singleton.instance = this; 
  this.data = {}; 
  return this; 
 } 

 getData(key) { 
 return this.data[key]; 
 } 

 setData(key, value) { 
 this.data[key] = value; 
 } 

}

const instance1 = new Singleton(); 
const instance2 = new Singleton(); 
instance1.setData('name', 'SingletonPattern'); 
console.log(instance2.getData('name'));  
console.log(instance1 === instance2); 

Comme indiqué ci-dessus, nous avons essayé de créer deux objets différents instance1 et instance2 qui sont strictement égales, ce qui signifie que les deux références sont à la même instance, la sortie sera true.

Voyons maintenant un exemple réel dans lequel nous utilisons une classe singleton pour créer une base de données dans un projet dactylographié. Nous aurons 2 fichiers, db.ts pour créer une connexion à la base de données et app.ts, qui accédera à l’objet de la base de données.

//db.ts

import { MongoClient } from 'mongodb';

class Database {

private static instance: Database;

private client: MongoClient;

private connectionString: string = 'YOUR_MONGO_URI_CONNECTION_STRING';

private constructor() {}

public static getInstance(): Database {

  console.log('Get Db Instance')

  if (!Database.instance) {

    console.log('Creating instance for the very first time')

    Database.instance = new Database();

}

return Database.instance;

}

public async connect(): Promise<MongoClient> {

  console.log('connecting to db....')

  if (!this.client) {

    this.client = new MongoClient(this.connectionString);

    await this.client.connect();

    console.log('Database connection established');

}

return this.client;

}

  public getClient(): MongoClient{
    if( !this.client ){
      this.client = new MongoClient(this.connectionString);
      await this.client.connect();
      console.log('Database connection established');

    }

    return this.client;
}

}

export default Database;
// App.ts

import Database from './db';

async function run() {

  try {

    const dbInstance = Database.getInstance();

    const dbInstance2 = Database.getInstance();

   
    // Lets create the database connection
    const client = await dbInstance.connect();

    const database = client.db('production');

    const collection = database.collection('partners');

    // Perform database operations

    const documents = await collection.find().toArray();

    console.log('Documents:', documents[0]);

    // lets check if both the clients from 2 instances are same or not?

    const client1 = dbInstance.getClient();

    const client2 = dbInstance2.getClient();

    console.log('Are both the clients same? -> ', client1===client2) // true

  } catch (error) {

    console.error('Error:', error);

  }

}

Dans l’exemple ci-dessus, le getInstance() méthode vérifie si le db l’instance existe déjà et la renvoie si disponible ; sinon, il en crée un nouveau. Chaque fois que nous récupérons le client Mongo en utilisant getClient() à partir de n’importe quelle instance du Database classe, il renverra toujours le même objet client créé initialement. Cela garantit une utilisation efficace des ressources, la cohérence des opérations de base de données et fournit un point de gestion centralisé pour la connexion à la base de données.

Avantages :

  • Accès contrôlé La classe Singleton a un accès strict sur sa seule instance sur comment et quand on y accède.
  • Gestion des ressources Les singletons peuvent aider à réduire la consommation de ressources, telles que l’utilisation de la mémoire et du processeur, en particulier pour les objets lourds comme les connexions à une base de données, en garantissant qu’une seule instance est créée.
  • Point d’accès mondial Le modèle Singleton fournit un point d’accès global unique à l’instance, ce qui facilite l’accès à l’instance depuis n’importe où dans l’application.
  • Cohérence – En fournissant un point d’accès unique à une ressource, le modèle Singleton garantit que toutes les parties d’une application sont alignées et cohérentes dans leur utilisation des ressources.

Inconvénients :

  • État global Ce modèle crée un état global dans une application, ce qui peut conduire à des dépendances cachées entre les classes et les modules, rendant le système plus difficile à déboguer.
  • Problèmes de concurrence Cela peut introduire des problèmes de concurrence dans les applications multithread. Lorsque plusieurs threads tentent d’instancier l’objet en même temps, cela peut entraîner la création de plusieurs objets au lieu de renvoyer une instance. Par conséquent, les développeurs doivent être au courant de la synchronisation à l’aide du verrouillage de thread ou du mutex dans les applications multithread.
  • Viole le SRP Il essaie de résoudre deux tâches en même temps, en garantissant qu’une classe n’aura qu’une seule instance et en attribuant un point d’accès global à l’instance de classe singleton. Cela viole donc le principe de responsabilité unique.
  • Problèmes de débogage L’ordre d’exécution est important. Lorsque plusieurs composants mettent à jour l’état, il peut être difficile de retracer les erreurs.

Conclusion

Le modèle Singleton fournit une approche structurée pour gérer les ressources partagées et simplifier l’accès aux objets requis globalement tels que les connexions à la base de données, les paramètres de configuration et les utilitaires de journalisation. Cela peut introduire des dépendances cachées, compliquer les tests et potentiellement devenir un goulot d’étranglement dans les systèmes distribués évolutifs. Il devient donc important d’évaluer judicieusement les avantages et les inconvénients et de les atténuer grâce à une conception et des tests minutieux.

VOUS TROUVEZ CECI UTILE ? PARTAGEZ-LE






Source link