싱글톤 디자인 패턴입니다. JS/TS 예제.

  • Implementation
  • Pros and Cons
  • Examples

  • 그렇다면 디자인 패턴을 알아야 하는 이유는 무엇일까요?

    우선 시간을 절약하는 데 도움이 됩니다. 프로그래밍은 새로운 것이 아니며 많은 문제가 이미 해결되었습니다. 많은 패턴과 접근 방식이 발명되었으며 대부분은 시간 테스트를 거쳤습니다. 바퀴를 재발명하고 싶지 않다면 기존 패턴과 접근 방식에 대해 더 알고 싶을 것입니다.
    따라서 디자인 패턴은 프로그래밍에서 일반적으로 발생하는 문제에 대한 일반적인 솔루션입니다.

    이 짧은 기사에서 우리는 싱글톤 디자인 패턴을 다룰 것입니다. 이 패턴은 창조적인 디자인 패턴의 한 유형이며 아마도 가장 간단한 패턴 중 하나일 것입니다.

    구현

    The Singleton pattern is just a way of creating a single object that is shared amongst a bunch of different resources throughout your application without having to recreate that object or losing the information inside of it.

    1. It ensures that there is only one instance of a given class
    For example we may create a logger class which prints logs and keeps them inside the class. Following this patters you have to have a single instance of the logger which prevents losing/overwriting the logs list.

    2. This pattern also provides a way to access the single instance globally
    Going back to our logger class, it's pretty much obvious that we need it to be accessible from any file in our project. Because errors may appear anywhere and we want to log them.

     

    장점과 단점

    Pros (Global variables vs Singleton):

    • Comparing to global variables, Singletons can not be modified(speaking of var in JS).
    • Unlike global variables it doesn't exist until instantiated.
    • Another advantage is that you are absolutely sure of the number of instances.
    • You can manage the state of that instance.

    Cons of using this design pattern:

    • Someday when you have a lot of parts of your app rely on that Singleton obj it may became hard to change Singleton obj itself.
    • As we already know Singleton's methods could be called from different parts of your app simultaneously at the same time which may cause a data/variables within this object to be overwritten/read incorrectly.

    FYI: there are more cons actually, but we're not going to cover all of them in this article.

     

    JS Example:

    class SingletonLogger {
      // prevent modifying the instance property,
      // for example set it to null to create a second instance.
      static #instance;
      // prevent modifying/overwriting logs array.
      #logs = [];
    
      // classes in JavaScript...
      //    may not have a private field named '#constructor'
      // so it's not possible to disable...
      //    calling constructor() {} in JS.
      // if you try new SingletonLogger()...
      //    with private constructor in TS it will throw an error
      constructor() {
        if (SingletonLogger.#instance) {
          throw new Error('Can not instantiate second singleton');
        }
        SingletonLogger.#instance = this;
      }
    
      // getInstance should be static...
      //    to be able to call SingletonLogger.getInstance()
      static getInstance() {
        if (!SingletonLogger.#instance) {
          SingletonLogger.#instance = new SingletonLogger();
        }
        return SingletonLogger.#instance;
      }
    
      log(error) {
        this.#logs.push(error);
        console.log(error);
      }
    
      // since #logs array is private, we need to create a getter
      get logsArray() {
        return this.#logs;
      }
    }
    
    // Usage:
    const logger = SingletonLogger.getInstance();
    try {
      throw new Error('first err');
    } catch(err) {
      logger.log(err); // log: first err
    }
    console.log(logger.logsArray); // log: [first err]
    
    const logger2 = SingletonLogger.getInstance();
    try {
      throw new Error('second err');
    } catch(err) {
      logger2.log(err); // log: second err
    }
    console.log(logger2.logsArray); // log: [first err, second err]
    
    // const logger3 = new SingletonLogger();
    // Error: Can not instantiate second singleton
    
    

    TS example:

    class SingletonLogger {
        private static instance: SingletonLogger;
        private logs: Array<Error> = [];
    
        private constructor() { }
    
        public static getInstance(): SingletonLogger {
            if (!SingletonLogger.instance) {
                SingletonLogger.instance = new SingletonLogger();
            }
            return SingletonLogger.instance;
        }
    
        log(error: Error) {
            this.logs.push(error);
            console.log(error);
        }
    
        get logsArray() {
            return this.logs;
        }
    }
    
    // Usage:
    // const singleton = new SingletonLogger(); // ...
    //    TS won't let you do this
    // Constructor of class 'SingletonLogger' is private...
    //    and only accessible within the class declaration.
    
    const singleton = SingletonLogger.getInstance();
    try {
        throw new Error('first err');
    } catch(err) {
        singleton.log(err as Error); // log: first err 
    }
    console.log(singleton.logsArray); // log: [first err] 
    
    const sameSingleton = SingletonLogger.getInstance();
    try {
        throw new Error('second err');
    } catch(err) {
        sameSingleton.log(err as Error); // log: second err 
    }
    console.log(sameSingleton.logsArray); // log: [first err, second err] 
    

     

    결론



    솔직히 싱글톤 디자인 패턴이 정말 도움이 될 프론트 엔드 개발의 사용 사례를 찾지 못했습니다. 물론 위에서 했던 것과 동일한 로거를 생성하거나 캐시를 싱글톤 객체로 사용할 수 있습니다. 하지만 개인적으로 거의 사용할 필요가 없을 것이라고 생각합니다.
    어쨌든 이 디자인 패턴은 Gang of Four design patterns의 일부이며 이러한 패턴을 모두 알면 개발자로서 다음 단계로 이동할 수 있습니다.

    읽어 주셔서 감사합니다! 어떤 피드백이든 감사합니다!😊

    Photo by Lucas Campoi

    좋은 웹페이지 즐겨찾기