[Design Pattern] Singleton Pattern

Main·2024년 8월 15일
0

Design Pattern

목록 보기
3/7

Singleton Pattern(싱글톤 패턴) ?

싱글톤 패턴(Singleton Pattern)은 객체 지향 프로그래밍에서 특정 클래스의 인스턴스가 오직 하나만 존재하도록 보장하는 디자인 패턴입니다. 이 패턴은 특정한 자원이나 상태를 공유해야 하는 경우에 유용하게 사용됩니다.

singleton_pattenr.png


Singleton Pattern의 특징

  • 유일한 인스턴스 보장: 클래스에 대해 단 하나의 인스턴스만 존재하며, 이 인스턴스는 애플리케이션 전반에서 공유됩니다.
  • 전역 접근 가능: 인스턴스는 전역적으로 접근 가능하며, 어디서든 동일한 인스턴스를 사용할 수 있습니다.
  • 지연 초기화(Lazy Initialization): 필요할 때 인스턴스를 생성하며, 인스턴스가 필요하지 않다면 생성되지 않습니다.
  • private 생성자: 외부에서 인스턴스 생성이 불가능하도록 생성자를 private으로 설정합니다.
  • Thread-safe 구현 가능: 멀티스레드 환경에서 안전하게 사용할 수 있도록 싱글톤 패턴을 구현할 수 있습니다.

Singleton Pattern의 장점

  • 메모리 절약: 하나의 인스턴스만 사용하기 때문에 메모리 사용을 최소화할 수 있습니다.
  • 리소스 관리 용이: 전역 인스턴스를 통해 리소스를 효율적으로 관리할 수 있습니다. 예를 들어, 데이터베이스 연결과 같은 비용이 많이 드는 리소스를 단일 인스턴스로 관리합니다.
  • 글로벌 상태 관리: 애플리케이션 전역에서 동일한 인스턴스를 사용하므로, 글로벌 상태를 일관되게 관리할 수 있습니다.

Singleton Pattern의 단점

  • 테스트 어려움: 싱글톤 인스턴스는 전역적이기 때문에 테스트 환경에서 상태를 초기화하거나 인스턴스를 교체하는 것이 어려울 수 있습니다.
  • 의존성 숨김: 클래스가 싱글톤 인스턴스를 내부에서 직접 호출하게 되면, 의존성이 명시적으로 드러나지 않아 코드의 가독성이 떨어질 수 있습니다.
  • 멀티스레드 문제: 싱글톤 패턴을 제대로 구현하지 않으면, 멀티스레드 환경에서 여러 인스턴스가 생성되는 문제가 발생할 수 있습니다. 이를 방지하기 위해 동기화 처리가 필요합니다.

Singleton Pattern 구현하기

1 ) 전역 변수를 통한 인스턴스 관리

let instance: Singleton;

export class Singleton {
  count: number;
  constructor(initalCount: number) {
    this.count = initalCount;
    if (instance) {
      return instance;
    }
    instance = this;
  }

  getInstance() {
    return this;
  }

  getCount() {
    return this.count;
  }

  increment() {
    this.count += 1;
  }

  decrement() {
    this.count -= 1;
  }
}

const singleton1 = new Singleton(0);
const singleton2 = new Singleton(10); // 기존 인스턴스 사용 count 10으로 초기화 x

const instance1 = singleton1.getInstance();
const instance2 = singleton2.getInstance();

console.log(instance1 === instance2); // true instance가 일치

singleton1.increment(); // 0 => 1
console.log(singleton1.getCount()); // 1
singleton2.decrement(); // 1 => 0 처음 설정한 sington1의 instance 바로보고 있기 때문
console.log(singleton2.getCount()); // 0 처음 설정한 sington1의 instance 바로보고 있기 때문

2 ) private 생성자와 정적 메서드를 통한 인스턴스 관리

export class Singleton {
  private static instance: Singleton;
  private count: number;

  // private 생성자: 외부에서 직접 인스턴스를 생성하지 못하도록 함
  private constructor(initialCount: number) {
    this.count = initialCount;
  }

  // Singleton 인스턴스를 반환하는 정적 메서드
  public static getInstance(initialCount: number = 0): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton(initialCount);
    }
    return Singleton.instance;
  }

  public getCount(): number {
    return this.count;
  }

  public increment(): void {
    this.count += 1;
  }

  public decrement(): void {
    this.count -= 1;
  }
}

// 사용 예시
const singleton1 = Singleton.getInstance(0);
const singleton2 = Singleton.getInstance(10); // 기존 인스턴스 반환, 초기값 10 무시

console.log(singleton1 === singleton2); // true, instance가 동일

singleton1.increment(); // 0 => 1
console.log(singleton1.getCount()); // 1
singleton2.decrement(); // 1 => 0
console.log(singleton2.getCount()); // 0, 동일한 인스턴스 사용

3 ) function형으로 구현

  • 클로저를 이용한 인스턴스 관리: Singleton 변수는 즉시 실행 함수(IIFE)를 통해 정의됩니다. 이 함수는 instance라는 변수를 클로저로 가지고 있어 외부에서 직접 접근할 수 없습니다.
  • createInstance 함수: 새로운 싱글톤 인스턴스를 생성하는 내부 함수입니다. 이 함수는 count 상태를 유지하며, 인스턴스가 처음 생성될 때만 호출됩니다.
  • getInstance 메서드: 외부에서 접근 가능한 메서드로, 이미 인스턴스가 존재하면 그 인스턴스를 반환하고, 존재하지 않으면 새로운 인스턴스를 생성합니다.
interface Singleton {
  getCount(): number;
  increment(): void;
  decrement(): void;
}

const Singleton = (() => {
  let instance: Singleton | null = null;

  function createInstance(initialCount: number): Singleton {
    let count = initialCount;

    return {
      getCount() {
        return count;
      },
      increment() {
        count += 1;
      },
      decrement() {
        count -= 1;
      }
    };
  }

  return {
    getInstance(initialCount: number = 0): Singleton {
      if (!instance) {
        instance = createInstance(initialCount);
      }
      return instance;
    }
  };
})();

// 사용 예시
const singleton1 = Singleton.getInstance(0);
const singleton2 = Singleton.getInstance(10); // 기존 인스턴스 반환, 초기값 10 무시

console.log(singleton1 === singleton2); // true, instance가 동일

singleton1.increment(); // 0 => 1
console.log(singleton1.getCount()); // 1
singleton2.decrement(); // 1 => 0
console.log(singleton2.getCount()); // 0, 동일한 인스턴스 사용

정리

싱글톤 패턴은 애플리케이션 전역에서 하나의 인스턴스를 공유하여 사용하고자 할 때 매우 유용한 디자인 패턴입니다. 메모리 절약, 리소스 관리 용이성, 글로벌 상태 관리 등의 장점이 있지만, 테스트의 어려움, 의존성 숨김, 멀티스레드 환경에서의 주의 사항과 같은 단점도 존재합니다. 따라서 싱글톤 패턴을 사용할 때는 이러한 장단점을 충분히 고려한 후, 적절한 상황에서 사용하는 것이 중요합니다.

profile
함께 개선하는 프론트엔드 개발자

0개의 댓글