[디자인 패턴-patters.dev] 1. 싱글톤 패턴

오재짱·2023년 4월 12일

이 포스트는 patterns.dev 사이트의 pattern에 대한 글들을 읽고 중요하다고 생각되는 부분만 추출해서 정리합니다.

싱글톤 패턴

싱글톤은 한 번만 인스턴스화 할 수 있고, 전역적으로 액세스할 수 있는 클래스입니다.
응용 프로그램 전체에서 공유할 수 있어 전역 상태를 관리하는데 적합합니다.

ES2015의 클래스를 사용한 싱글톤

let instance;
let counter = 0;
 
class Counter {
  constructor() {
    // 하나의 인스턴스만 만들수 있도록 한다.
    if (instance) {
      throw new Error("You can only create one instance!");
    }
    instance = this;
  }
 
  getInstance() {
    return this;
  }
 
  getCount() {
    return counter;
  }
 
  increment() {
    return ++counter;
  }
 
  decrement() {
    return --counter;
  }
}
// Obeject.freeze를 통해 consume 코드가 싱글톤을 수정하지 않도록 한다.
const singletonCounter = Object.freeze(new Counter());
export default singletonCounter;

이제 redButton.js파일과 blueButton.js 파일이 Counter를 사용했을때 같은 counter 값을 공유할 수 있게 됩니다. 다른 파일에서 메서드를 호출하더라도 모든 인스턴스간에 동일한 값이 공유됩니다.

// redButton.js 파일
import Counter from "./counter";

const button = document.getElementById("red");
button.addEventListener("click", () => {
  Counter.increment();
  console.log("Counter total: ", Counter.getCount());
});

// blueButton.js 파일
import Counter from "./counter";

const button = document.getElementById("blue");
button.addEventListener("click", () => {
  Counter.increment();
  console.log("Counter total: ", Counter.getCount());
});

장단점

인스턴스화를 하나로 제한하면 잠재적으로 많은 메모리 공간을 절약하는게 가능합니다. 매번 새로운 인스턴스의 메모리를 설정하는것 대신 앱 전체에서 참조되는 인스턴스에 대한 메모리만 설정하면 됩니다.
하지만 싱글톤은 실제로 안티패턴으로 간주되어 자바스크립트에서는 피하는것이 좋습니다.

Java 또는 C++과 같은 프로그래밍 언어에서는 객체를 생성하는 클래스를 생성해야만 합니다.
하지만 자바스크립트는 객체를 직접 생성하는것이 가능해 위 예제와 같이 과도한 구현이 필요없습니다.

일반 객체 사용

아래와 같이 간단하게 구현해도 위 예제 코드와 같은 결과를 얻는것이 가능합니다.

let count = 0;

const counter = {
  increment() {
    return ++count;
  },
  decrement() {
    return --count;
  }
};

Object.freeze(counter);
export { counter };

객체는 참조로 전달되기 때문에 같은 count 값을 공유하는것이 가능합니다.

테스트

싱글톤에 의존하는 테스트 코드는 까다로울 수 있습니다. 매번 새로운 인스턴스를 만들 수 없기 때문에 이전 테스트의 결과가 이후의 테스트에도 영향을 끼칠 수 있습니다. 테스트 후에 테스트에 의해 수정된 사항을 재설정하기 위해서는 전체 인스턴스를 재설정하는 과정이 필요합니다.

명확하지 않은 의존

다른 모듈로부터 import될 때 싱글톤인지 명확하게 알 수 없습니다. 여러 싱글톤 인스턴스들이 앱에서 공유될 때 직접 수정할 수도 있고 예외로 이어질 수도 있습니다.

전역 동작

싱글톤 인스턴스는 전체 앱에서 참조될 수 있어야 하므로 전역 변수와 같이 동작합니다.
전역 변수는 일반적으로 잘못된 설계 결정으로 간주합니다. 전역 변수의 값을 실수로 덮어쓰는 등의 전역 스코프 오염이 생길 수 있어 예기치 않은 동작이 발생할 수 있기 때문입니다.
ES2015에서는 let, const와 같은 키워드를 통해 변수를 블록 범위로 유지해 전역 스코프를 오염시키는것을 방지합니다.
자바스크립트의 경우 export와 import를 통해 module의 값을 추출하고 가져오며 전역 스코프를 오염시키지 않을 수 있습니다.

전역 상태를 사용하면 앱이 커지면 커질수록 데이터 흐름(실행 순서)을 이해하는데에 있어서 매우 까다로울 수 있습니다.

리액트 상태 관리

리액트에서는 싱글톤을 사용하는 대신에 Redux, React Context와 같은 상태 관리 도구를 사용합니다.
싱글톤과 비슷해 보일 수 있지만 읽기 전용 상태를 제공한다는 점에서 다릅니다.

전역 상태의 단점이 사라지지는 않지만 구성 요소가 상태를 직접 업데이트 하는 것이 불가능하기 때문에 적어도 전역 상태의 변경을 의도한대로 적용할 수 있습니다.

profile
'설명하지 못하면 이해한게 아니다'라는 마음가짐을 가진 프론트엔드 지망생에서 프론트엔드 개발자가 됬습니당!

0개의 댓글