본문 바로가기
BE 공부/클린 코드

[디자인 패턴 입문] Singleton(싱글턴)

by 꼬질꼬질두부 2025. 7. 2.
반응형

1. 개념 정리

싱글턴(Singleton)은 프로그램 전체에서 단 하나의 객체만 생성되도록 보장하는 디자인 패턴입니다.
이 패턴은 여러 위치에서 동일한 설정, 로그 기록, 데이터베이스 연결 같은 기능을 사용할 때 유용합니다.

 

자바스크립트에서는 모듈 시스템(CommonJS 또는 ESModules)이 싱글턴처럼 동작합니다.
한 번 불러들인 모듈은 이후에는 새로 실행되지 않고, 처음 불러온 결과를 계속 재사용하게 됩니다.
따라서 하나의 모듈이 생성한 객체는 애플리케이션 전반에서 공유됩니다.

이러한 구조로, JS에서는 싱글턴을 많이 활용합니다.

2. 예제 코드

가장 기본적인 싱글턴 구현

class Config {
  constructor() {
    if (Config.instance) {
      return Config.instance; // 이미 생성된 인스턴스를 반환합니다
    }
    this.settings = {};
    Config.instance = this; // 처음 생성된 인스턴스를 저장합니다
  }

  set(key, value) {
    this.settings[key] = value;
  }

  get(key) {
    return this.settings[key];
  }
}

// 사용 예
const config1 = new Config();
config1.set("theme", "dark");

const config2 = new Config();
console.log(config2.get("theme")); // 'dark' 출력 - 같은 인스턴스를 공유함

모듈 기반 싱글턴 (추천 방식)

// config.js
const config = {
  settings: {},
  set(key, value) {
    this.settings[key] = value;
  },
  get(key) {
    return this.settings[key];
  }
};

module.exports = config;
// main.js
const config = require('./config');
config.set("lang", "ko-KR");
console.log(config.get("lang")); // 'ko-KR'

Node.js에서 require()로 모듈을 불러올 경우, 해당 모듈은 한 번만 실행되며 동일한 객체를 재사용합니다.

3. 언제 사용하면 좋을까? (하나의 인스턴스가 필요한 상황)

1) 환경 설정 관리

예시 상황

개발/운영 환경, 테마, 언어 설정 등 프로그램 전체에서 공통으로 사용되는 설정을 여러 파일에서 참조해야 할 때

예시 코드

// settings.js
module.exports = {
  env: 'production',
  language: 'ko-KR'
};

// main.js
const settings = require('./settings');
console.log(settings.language); // 'ko-KR'

설명

환경 설정은 어디서든 같은 값을 사용해야 합니다.
이처럼 하나의 객체를 여러 위치에서 참조할 때 싱글턴이 적합합니다.


2) 데이터베이스 연결 관리

예시 상황

MySQL이나 MongoDB와 같은 데이터베이스에 연결할 때, 여러 파일에서 같은 연결을 공유해야 하는 경우

예시 코드

// db.js
let connection = null;

function connect() {
  if (!connection) {
    connection = { conn: 'DB 연결됨' }; // 실제 DB 연결 객체를 가정
  }
  return connection;
}

module.exports = { connect };
// userRepo.js
const db = require('./db');
const conn = db.connect();

설명

데이터베이스 연결은 자원이 많이 드는 작업입니다.
한 번만 연결하고, 여러 모듈에서 그 연결을 공유하면 효율적인 자원 관리가 가능합니다.


3) AWS SDK 리소스 관리

예시 상황

AWS S3나 DynamoDB와 같은 서비스를 사용할 때, 설정을 반복하지 않고 하나의 인스턴스를 여러 곳에서 사용할 필요가 있을 때

예시 코드

// awsClient.js
const AWS = require('aws-sdk');
const s3 = new AWS.S3({ region: 'ap-northeast-2' });
module.exports = s3;
// uploader.js
const s3 = require('./awsClient');
s3.upload(/* ... */);

설명

AWS 객체는 리전(region)이나 자격 증명 같은 설정이 필요합니다.
매번 객체를 새로 만들면 설정을 반복해야 하므로, 하나의 객체를 재사용하는 방식이 더 효율적입니다.


4. 주의사항 (문제와 해결 방법)

전역 상태로 인한 테스트 문제

  • 싱글턴은 프로그램 전역에서 하나의 객체를 공유합니다.
  • 테스트 코드에서 하나의 테스트가 설정을 바꾸면, 다른 테스트 결과에 영향을 줄 수 있습니다.

해결 방법: 테스트 전에 매번 상태를 초기화하거나, 상태를 가지지 않는 싱글턴을 만드는 것이 좋습니다.

의존성 관리가 어려워질 수 있음

  • 싱글턴은 어디에서든 접근할 수 있기 때문에, 어떤 코드가 어떤 객체를 사용하는지 파악하기 어려울 수 있습니다.
  • 이런 방식은 의존성을 명확하게 드러내지 않으므로, 유지보수에 어려움이 생길 수 있습니다.

해결 방법: 싱글턴을 직접 불러오기보다는, 외부에서 필요한 객체를 주입받는 방식(의존성 주입)을 사용하면 좋습니다.


정리 요약

  • 싱글턴 패턴은 프로그램 전체에서 단 하나의 객체를 공유할 필요가 있을 때 유용합니다.
  • 환경 설정, DB 연결, AWS 리소스와 전역 리소스를 관리해야 하는 경우에 사용하기 적합합니다.
  • 자바스크립트에서는 모듈 시스템 자체가 싱글턴처럼 동작합니다.
  • 단, 테스트나 유지보수 측면에서 주의하며 사용합니다.
반응형

댓글