OOP

[JS] Singleton 패턴

gradu 2025. 4. 2. 20:54

Singleton 이 뭔데?

싱글톤을 공부하는 사람이라면

백엔드 공부를 시작한 지 얼마 안 됐거나

게임 개발을 제대로 찍어먹어보다가 싱글톤을 마주쳤거나

여타 다른 분야의 필요한 객체지향을 공부하다가 만난 경우가 대부분일 것이다

 

되게 많이 등장하긴 하는데 그래서 이게 뭐냐고..

 

Singleton 은 객체 지향 패턴의 베스트 셀러인 디자인 패턴의 기초적인 예시이다

 

???

 

풀어서 설명하면 "객체 지향 프로그래밍" 을 하다보면 자주 사용되는 패턴들이 있는데,

그걸 고대의 프로그래머들이 정리해놓은게 "디자인 패턴" 이고,

그 중 베스트 셀러가 20개 남짓인데,

그 중에서도 가장 많이 언급되는 친구가 이 "싱글톤"이다

 

오늘은 이 싱글톤에 대해서 자세히 알아보겠다


 #    구조 

// Singleton.js

let instance = null;

class Singleton {
  constructor() {
    if(!instance) {
      this.data = null;
      instance = this;
    }
    return instance;
  }

  setData(data) {
    this.data = data;
  }

  getData() {
    return this.data;
  }

  // methods
  // ...
}

export default Singleton;



// anywhere in app

import Singleton from './Singleton';

const singleton_a = new Singleton();
const singleton_b = new Singleton();

console.log(singleton_a === singleton_b);
// true

 

JavaScript 에서 module 을 활용한 싱글톤은 위와 같이 작성할 수 있다

 

먼저 인스턴스를 참조할 instance 변수를 선언한다

 

생성자 함수가 호출되면 이 instance 변수가 객체를 참조하고 있는 지 검사한 뒤

참조가 없다면 새로운 객체를 만들어서 넣어준다

하지만 참조가 있다면 참조하고 있는 그 객체를 그대로 반환한다

 

따라서 외부 모듈에서 이 Singleton 클래스를 import 해서 객체를 아무리 많이 찍어내도

생성자 함수가 항상 같은 객체를 반환할 것이다

 

코드에서는 콘솔에 직접 같은 지 찍어봄으로써 확인하고 있다

 

instance 변수는 export 되지 않았으므로 외부 모듈의 코드로부터 안전을 보장받는다

 

개발자가 설계한 싱글톤 클래스의 메소드에 의해서만 변경될 수 있으므로

이 클래스에서 관리하는 데이터에 문제가 생겼을 경우

다른 코드가 해당 데이터를 건드렸을 가능성을 배제하고 디버깅을 진행할 수 있다

 

아래의 순서도와 함께 보면 이해하기 한결 편할 것이다


 #    인스턴스 생성 과정 순서도 

 


 #    실제 활용 예시 

// AuthService.js

class AuthService {
  constructor() {
    this.token = null;
  }

  setToken(t) {
    this.token = t;
  }

  getToken() {
    return this.token;
  }

  isAuthenticated() {
    return !!this.token;
  }
}

const instance = new AuthService();
export default instance;

// anywhere in app
import AuthService from './AuthService';

AuthService.setToken('abc123');
if (AuthService.isAuthenticated()) {
  console.log('User is logged in');
}

 

이 코드는 내가 실제로 참여 중인 프로젝트의 인증 상태 관리 부분을 간소화한 버전이다

 

실제로는 클래스가 아닌 컴포넌트로 이루어져있지만 둘 다 함수객체이므로 내부적으로는 매우 유사하다

 

사용자의 인증 상태를 검증할 기준값인 token 을 백엔드로부터 전송받고 이후 AuthService 라는 클래스의 객체로 관리할 계획이다

 

app 이 실행되고 브라우저가 모듈 의존성을 조사하여 AuthService 모듈을 실행하는 순간 instance 가 초기화 된다

 

instance 의 구현 방식을 담고 있는 class 는 외부에 노출시키지 않고 instance 만 export 시켜서 접근을 허용한다

 

이렇게 하면 인증 상태에 관한 정보를 하나의 인스턴스가 독점적으로 관리하여 다른 코드에서 필요로 하는 정보를 일관적으로 뿌려줄 수 있다


객체 지향을 공부하면서 가장 짜릿한 점은 계층 정복에 대한 체감이다

 

한 계층을 기능적으로 사용하는 법을 공부하고,

 

기능의 원리를 분석하고,

 

원리를 바탕으로 기능을 일반화하고,

 

자주 쓰이는 형태를 패턴화하고 나면?

 

마치 해당 계층을 정복한 것과 같은 기분이 든다

 

정복하는 과정에서 어떤 형태로든 ( 뇌 혹은 외부 저장소에 ) 아카이빙을 철저히 해준다면 성장 속도가 기하급수적으로 증가할 것이라고 믿는다

 

그럴려면 블로그 열심히 써야겠다...